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

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

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

这是我的测试代码。 基本上我只是开始两个任务,他们都尝试用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); 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); Debug.WriteLine("leaving lock2"); }, "SELECT * FROM MyEntities WITH (UPDLOCK, HOLDLOCK) WHERE Id = @param1", new SqlParameter("param1", 1)); }); 

输出窗口:

 entered into lock1 entered into lock2 leaving lock2 leaving lock1 

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

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

所以在夏季: 锁定选择:否则由EF /是本机SQL

锁定更新

在DB中修改行时,修改的行会获得某种lock 。 锁的类型由正在运行的TransactionIsolation Level确定。 SQL Server中的Isolation Level的默认值为“已Read Committed ,这意味着在当前事务中修改的所有行都将获得Shared锁。 此锁与SELECT兼容,但与UPDATEDELETE不兼容。 这意味着当您修改事务中的行时,默认情况下保证没有其他并行线程可以推断和更改它们,直到您通过COMMITROLLBACK结束事务。

  • 要了解SQL Server中的锁,请参阅: http : //technet.microsoft.com/en-us/library/aa213039(v = sql.80).aspx
  • 要了解事务隔离级别,请参阅: http : //technet.microsoft.com/en-us/library/ms189122(v = sql.105).aspx

更新:

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

 Example: SELECT * FROM MyTable WITH (XLOCK, PAGLOCK) 

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