首先在 EF 代码中悲观锁定
本文关键字:悲观 锁定 代码 EF | 更新日期: 2023-09-27 18:34:52
我想专门锁定表中的指定行,因此在实际事务完成之前不允许读取任何更新。为此,我在数据库存储库中创建了一个帮助程序类:
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();
}
}
这是我的测试代码。基本上,我刚刚开始两个任务,它们都尝试使用 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));
});
输出窗口:
entered into lock1
entered into lock2
leaving lock2
leaving lock1
您所要求的内容涉及DBMS中的两个主要现象,特别是在SQL Server中:Lock
和Isolation Level
。我尽力在夏天解释它们。
你问的是Pessimistic Concurrency
.答案是:实体框架尚不支持它。换句话说,通过EF的传统API,您无法锁定表或某些行SELECT
例如Oracle
通过SELECT FOR UPDATE
。尽管您可以通过编写本机 SQL
命令来选择具有Exclusive
锁的某些行或整个表并保持此锁直到事务结束来实现此目的。这样,其他线程不仅无法更新所选行,而且无法选择它们。它们会被阻止,直到您松开锁。这就是我在项目中所做的,虽然有些风险,但它工作正常。
所以在夏天:锁定选择: EF 的 NO/本机 SQL 的 YES
锁定更新:
当您修改数据库中的行时,修改后的行会获得某种lock
。锁的种类由运行Transaction
的Isolation Level
决定。SQL Server 中 Isolation Level
的默认值为 Read Committed
这意味着在当前事务中修改的所有行都将Shared
锁定。此锁与SELECT
兼容,但与UPDATE
或DELETE
不兼容。这意味着当您修改事务中的行时,默认情况下可以保证没有其他并行线程可以推断和更改它们,直到您通过 COMMIT
或 ROLLBACK
结束事务。
- 要了解 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
.
更新:
表提示UPDLOCK and HOLDLOCK
可能会被查询优化器或其他 DBMS 模块忽略,因为它们只是提示 :-(。唯一肯定强制执行的表提示组合是 (XLOCK, PAGLOCK)
。
Example: SELECT * FROM MyTable WITH (XLOCK, PAGLOCK)
正如我所说,手动锁定是有风险的。以最大的考虑度使用它。