【发布时间】:2015-11-19 18:20:19
【问题描述】:
我使用实体框架来处理长时间运行的任务(平均 10-30 秒)。我有许多工作人员实例,每个工作人员从数据库表中获取下一个任务 ID,然后它会获取该 ID 的工作描述。
当然,对任务表的访问必须是序列化的,这样来自worker的每个请求都会得到一个新的id。我认为这样做可以:
static int? GetNextDetailId()
{
int? id = null;
using ( var ctx = Context.GetContext() )
using ( var tsx = ctx.Database.BeginTransaction( System.Data.IsolationLevel.Serializable ))
{
var obj = ctx.DbsInstrumentDetailRaw.Where( x => x.ProcessState == ProcessState.ToBeProcessed ).FirstOrDefault();
if ( obj != null )
{
id = obj.Id;
obj.ProcessState = ProcessState.InProcessing;
ctx.SaveChanges();
}
tsx.Commit();
}
return id;
} // GetNextDetailId
不幸的是,当我与 10 名工人一起运行它时,我几乎立即得到了
事务(进程 ID 65)在锁定资源上与另一个进程死锁,并已被选为死锁牺牲品。重新运行事务。
我对这种行为没有任何解释。我知道死锁情况:我们有两个或更多资源和两个或更多进程试图以不同的顺序获取资源。但是这里我们只有一个资源!我想要的只是可以顺序访问此资源的进程。因此,如果 A 有一个事务打开,B 应该简单地等到 A 提交/回滚。这似乎不会发生在这里。
有人可以吗
阐明这里发生了什么,以教育我。
为问题提供一个(“THE?”)解决方案。我认为这个问题在编程中应该很常见。
谢谢 马丁
【问题讨论】:
-
默认隔离级别设置为可序列化,在使用中会产生不必要的阻塞和死锁。因此,建议您将默认隔离级别覆盖为 ReadCommitted,这反映了 SQL Server 中的默认值。
-
... 对不起,这与问题无关。请问解决方法?
-
不,Rookie,但只是建议它可以帮助减少死锁的数量,当你有更大程度的请求时。如果这是一个解决方案,会在下面发布。 :)
标签: c# entity-framework transactions database-deadlocks