首先对EF代码进行悲观锁定

las*_*s88 6 c# sql-server asp.net-mvc entity-framework locking

我想专门锁定我的表中的指定行,因此在实际事务完成之前不会读取任何更新.为此,我在数据库存储库中创建了一个辅助类:

public void PessimisticMyEntityHandler(Action<IEnumerable<MyEntity>> fieldUpdater, string sql, params object[] parameters)
{
    using (var scope = new System.Transactions.TransactionScope())
    {
        fieldUpdater(DbContext.Set<MyEntity>().SqlQuery(sql, parameters));
        scope.Complete();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的测试代码.基本上我只是开始两个任务,他们都尝试用Id'1'锁定行.我的猜测是第二个任务将无法读取(和更新)该行,直到第一个任务完成其作业,但输出窗口显示它实际上可以.

Task.Factory.StartNew(() =>
{
      var dbRepo = new DatabaseRepository();
      dbRepo.PessimisticMyEntityHandler(myEntities =>
      {
                Debug.WriteLine("entered into lock1");

                /* Modify some properties considering the current ones... */
                var myEntity = myEntities.First();
                Thread.Sleep(1500);
                myEntity.MyEntityCode = "abcdefgh";
                dbRepo.Update<MyEntity>(myEntity);

                Debug.WriteLine("leaving lock1");
     }, "SELECT * FROM MyEntities WITH (UPDLOCK, HOLDLOCK) WHERE Id = @param1", new SqlParameter("param1", 1));
});

Task.Factory.StartNew(() =>
{
      Thread.Sleep(500);
      var dbRepo = new DatabaseRepository();
      dbRepo.PessimisticMyEntityHandler(myEntities =>
      {
                Debug.WriteLine("entered into lock2");

                /* Modify some properties considering the current ones... */
                var myEntity = myEntities.First();
                myEntity.MyEntityCode = "xyz";
                dbRepo.Update<MyEntity>(myEntity);

                Debug.WriteLine("leaving lock2");
     }, "SELECT * FROM MyEntities WITH (UPDLOCK, HOLDLOCK) WHERE Id = @param1", new SqlParameter("param1", 1));
});
Run Code Online (Sandbox Code Playgroud)

输出窗口:

entered into lock1
entered into lock2
leaving lock2
leaving lock1
Run Code Online (Sandbox Code Playgroud)

Ali*_*eza 8

您要求的是DBMS中的两个主要现象,特别是在SQL Server中:LockIsolation Level.我尽力在夏天解释它们.

你问过Pessimistic Concurrency.答案是:实体框架中尚不支持它.换句话说,通过EF的传统API,您无法锁定表或某些行SELECT,例如Oracle通过via SELECT FOR UPDATE.虽然您可以通过编写本机SQL命令来选择某些行或使用Exclusive锁定整个表来实现此目的,并保持此锁定直到事务结束.这样,其他线程不仅无法更新所选行,也无法选择它们.它们会被阻塞,直到您释放锁定.这就是我在我的项目中所做的事情,虽然有点风险,但它运作正常.

所以总结:锁定选择:否则 EF /是本机SQL

锁定更新:

修改DB中的行时,修改后的行会获得某种形式lock.锁的类型由Isolation Level运行决定Transaction.Isolation LevelSQL Server中的默认值是Read Committed指当前事务中修改的所有行都获得Shared锁定.此锁SELECTUPDATE或不兼容DELETE.这意味着当您修改事务中的行时,默认情况下保证没有其他并行线程可以推断和更改它们,直到您通过COMMIT或结束事务ROLLBACK.

.

更新:

UPDLOCK and HOLDLOCK查询优化器或其他DBMS模块可能会忽略表提示,因为它们只是提示 :-).唯一可以强制执行的表提示组合(XLOCK, PAGLOCK).

Example: SELECT * FROM MyTable WITH (XLOCK, PAGLOCK)
Run Code Online (Sandbox Code Playgroud)

正如我所说,手动锁定是有风险的.在最大程度考虑时使用它.

  • 要点:SQL Server 永远不会忽略锁定命中。这是正确制作一些锁定模式所必需的。 (2认同)