【问题标题】:How to prevent EntityFramework deadlock when concurrently running these two statements并发运行这两条语句时如何防止EntityFramework死锁
【发布时间】:2012-10-27 04:13:57
【问题描述】:

调用我的网络服务使用以下代码来确保调用者有一个有效的会话。如果找到有效会话,则它会更新会话详细信息并保存更改。一切都很简单,而且工作正常。

// 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;
     }    
}

在同一个调用者(因此同一个会话)进行多个并发调用之前,一切正常(这是完全有效的)。在这种情况下,我有时会陷入僵局。使用 SQL Server Profiler,我可以看到正在发生以下情况。

调用者 A 执行选择并获取用户会话上的共享锁。调用者 B 执行选择并获取同一用户会话上的共享锁。由于调用者 B 的共享锁,调用者 A 无法执行其更新。由于调用者 A 的共享锁,调用者 B 无法执行其更新。死锁。

这似乎是一个简单而经典的死锁场景,必须有一个简单的方法来解决它。当然,几乎所有现实世界的应用程序都存在同样的问题。但是我在实体框架的书籍中没有提到任何关于死锁的内容。

【问题讨论】:

    标签: c# entity-framework deadlock


    【解决方案1】:

    我发现一篇文章谈到了这个HERE。听起来您基本上可以启动和停止围绕您的 EF 调用的事务...该块提供了以下代码示例,因此归功于 Diego B Vega... 该博客文章还链接到另一个包含其他信息的博客。

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

    【讨论】:

    • 我可以问这个问题吗? using(MyContext ctx ..) 应该在 using(var scope = new TransactionScope) 内还是相反?谢谢。
    • 我相信您会希望TransactionScope 位于MyContext 的内部。在我的脑海里只是想着它......因为事务被用于用于上下文......当事务完成时上下文需要存在。不过这里可能是错的。
    【解决方案2】:

    以下内容对您有用吗?

    using(MyContext ctx = CreateMyContext())
    {
    
         ctx.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
    
    
         // Get the user session for the client session         
         ...
    }
    

    【讨论】:

      【解决方案3】:

      您可能让每个会话都使用事务?在这种情况下,它们将死锁,因为事务在尝试保存时都尝试从共享锁升级到独占锁。这似乎没有很好的记录,因为 EF 支持乐观并发。

      解决此问题的一种方法是使用以下内容提供更新锁提示:

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

      见:entity framework 6 and pessimistic concurrency

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-02
        • 1970-01-01
        • 2021-03-22
        • 1970-01-01
        相关资源
        最近更新 更多