简体   繁体   English

同时运行这两个语句时如何防止EntityFramework死锁

[英]How to prevent EntityFramework deadlock when concurrently running these two statements

Calls into my web service use the following code to ensure that the caller has a valid session.调用我的 Web 服务使用以下代码来确保调用者具有有效的会话。 If a valid session found then it updates the session details and saves the changes.如果找到有效会话,则它会更新会话详细信息并保存更改。 All simple enough and works fine.一切都很简单,而且工作正常。

// Create the Entity Framework context
using(MyContext ctx = CreateMyContext())
{
     // Get the user session for the client session         
     UserSession session = (from us in context.UserSessions.Include("UserEntity")
                            where us.SessionId = callerSessionId
                            select us).FirstOrDefault<UserSession>();

     if (session == null)
         return false;
     else
     {
         // Update session details
         session.Calls++;
         session.LastAccessed = DateTime.Now.Ticks;
         Console.WriteLine("Call by User:{0}", session.UserEntity.Name);

         // Save session changes back to the server
         ctx.SaveChanges();
         return true;
     }    
}

All works fine until the same caller, and hence the same session, makes multiple concurrent calls (which is perfectly valid to happen).一切正常,直到同一个调用者,因此同一个会话,进行多个并发调用(这是完全有效的)。 In this case I sometimes get a deadlock.在这种情况下,我有时会陷入僵局。 Using SQL Server Profiler I can see the following is happening.使用 SQL Server Profiler 我可以看到以下情况发生。

Caller A performs the select and acquires a shared lock on the user session.调用方 A 执行选择并获取用户会话上的共享锁。 Caller B performs the select and acquires a shared lock on the same user session.调用方 B 在同一个用户会话上执行选择并获取共享锁。 Caller A cannot perform its update because of Caller B's shared lock.由于调用者 B 的共享锁,调用者 A 无法执行其更新。 Caller B cannot perform its update because of caller A's shared lock.由于调用者 A 的共享锁,调用者 B 无法执行其更新。 Deadlock.僵局。

This seems like a simple and classic deadlock scenario and there must be a simple method to resolve it.这似乎是一个简单而经典的死锁场景,必须有一个简单的方法来解决它。 Surely almost all real world applications have this same problem.But none of the Entity Frameworks books I have mention anything about deadlocks.当然,几乎所有现实世界的应用程序都有同样的问题。但我没有提到任何关于死锁的实体框架书籍。

I found an article that talks about this HERE .我在这里找到了一篇关于这个的文章。 It basically sounds like you can start and stop a transaction that surrounds your EF call... The block gives the following code example so credit goes to Diego B Vega... The blog post also links to another blog with additional information.基本上听起来您可以启动和停止围绕您的 EF 调用的事务……该块提供了以下代码示例,因此应归功于 Diego B Vega……该博客文章还链接到另一个包含其他信息的博客。

using (var scope = new TransactionScope(TransactionScopeOption.Required, new 
    TransactionOptions { IsolationLevel= IsolationLevel.Snapshot }))
{
    // do something with EF here
    scope.Complete();
}

Will the following work for you?以下对你有用吗?

using(MyContext ctx = CreateMyContext())
{

     ctx.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");


     // Get the user session for the client session         
     ...
}

You probably have each session using a transaction maybe?您可能每个会话都使用事务? in which case they will deadlock as the transactions both try to upgrade from shared lock to exclusive lock when they attempt to save.在这种情况下,它们将死锁,因为事务在尝试保存时都尝试从共享锁升级到排他锁。 This seems to be not well documented since EF favours optimistic concurrency.这似乎没有得到很好的记录,因为 EF 支持乐观并发。

One way out of this is to provide an updatelock hint using something like this:解决此问题的一种方法是使用以下内容提供更新锁提示:

return context.TestEntities
          .SqlQuery("SELECT TOP 1 Id, Value FROM TestEntities WITH (UPDLOCK)")
          .Single();
}

see: entity framework 6 and pessimistic concurrency参见: 实体框架 6 和悲观并发

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM