根据C#中的条件保护关键部分

时间:2010-05-26 16:06:48

标签: c# multithreading conditional critical-section

我正在处理一个很糟糕的场景。

我正在使用EntityFramework将(插入/更新)保存到多线程环境中的SQL数据库中。问题是我需要访问数据库以查看是否已经创建了具有特定键的寄存器以设置字段值(执行)或者它是否为新设置不同的值(待定)。这些寄存器由唯一的guid标识。

我通过设置锁来解决这个问题,因为我知道实体不会出现在任何其他进程中,换句话说,我将在不同的进程中没有相同的guid,它似乎工作正常。看起来像这样:

static readonly object LockableObject = new object();
static void SaveElement(Entity e)
{
       lock(LockableObject)
       {
           Entity e2 = Repository.FindByKey(e);
           if (e2 != null)
           {
               Repository.Insert(e2);
           }
           else
           {
               Repository.Update(e2);
           }
       }
}

但这意味着当我有大量的请求被保存时,它们将排队等候。

我想知道是否有类似的东西(请把它作为一个想法):

static void SaveElement(Entity e)
{
       (using ThisWouldBeAClassToProtectBasedOnACondition protector = new ThisWouldBeAClassToProtectBasedOnACondition(e => e.UniqueId)
       {
           Entity e2 = Repository.FindByKey(e);
           if (e2 != null)
           {
               Repository.Insert(e2);
           }
           else
           {
               Repository.Update(e2);
           }
       }
}

这个想法是有一种基于条件保护的保护,因此每个实体e都有自己的基于e.UniqueId属性的锁。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

不要使用需要数据库事务或约束的应用程序锁。

使用锁来防止数据库中的重复条目不是一个好主意。它限制了应用程序的可伸缩性,只强制存在可以添加或更新此类记录的单个实例。或者更糟糕的是,有人最终会尝试将应用程序扩展到多个进程或服务器,这会导致数据损坏(因为锁是单个进程的本地锁)。

您应该考虑的是在数据库和事务中使用唯一约束的组合,以确保添加相同条目的两次尝试都不会成功。一个人会成功 - 另一个人将被迫回滚。

答案 1 :(得分:0)

这可能对你有用,你可以锁定e:

的实例
   lock(e)
   {
       Entity e2 = Repository.FindByKey(e);
       if (e2 != null)
       {
           Repository.Insert(e2);
       }
       else
       {
           Repository.Update(e2);
       }
   }