我想独占地锁定表中的指定行,因此在实际事务完成之前不会读取任何更新。为此,我在数据库存储库中创建了一个辅助类:
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
答案 0 :(得分:8)
您要求的是DBMS中的两个主要现象,特别是在SQL Server中:Lock
和Isolation Level
。我尽力在夏天解释它们。
你问过Pessimistic Concurrency
。答案是:实体框架中尚不支持它。换句话说,通过EF的传统API,您无法锁定SELECT
的表格或某些行,例如Oracle
通过SELECT FOR UPDATE
执行的操作。虽然您可以通过编写本机SQL
命令来选择某些行或使用Exclusive
锁定的整个表来实现此目的,并保持此锁定直到事务结束。这样,其他线程不仅无法更新所选行,也无法选择它们。它们会被阻塞,直到您释放锁定。这就是我在我的项目中所做的,虽然风险很大,但它的工作正常。
所以总结: 锁定选择:否则为EF /是本机SQL
锁定更新:
修改DB中的行时,修改后的行会获得某种lock
。锁定类型由正在运行的Isolation Level
的{{1}}确定。 SQL Server中的Transaction
默认值为Isolation Level
,这意味着当前事务中修改的所有行都会锁定Read Committed
。此锁与Shared
兼容,但与SELECT
或UPDATE
不兼容。这意味着当您修改事务中的行时,默认情况下保证在DELETE
或COMMIT
结束事务之前,没有其他并行线程可以推断和更改它们。
<强>更新强>
查询优化器或其他DBMS模块可能会忽略表提示ROLLBACK
,因为它们只是提示 :-)。唯一可以强制执行的表提示组合是UPDLOCK and HOLDLOCK
。
(XLOCK, PAGLOCK)
正如我所说,手动锁定是有风险的。在最大程度考虑时使用它。