[英]How to prevent EntityFramework deadlock when concurrently running these two statements
調用我的 Web 服務使用以下代碼來確保調用者具有有效的會話。 如果找到有效會話,則它會更新會話詳細信息並保存更改。 一切都很簡單,而且工作正常。
// 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 無法執行其更新。 僵局。
這似乎是一個簡單而經典的死鎖場景,必須有一個簡單的方法來解決它。 當然,幾乎所有現實世界的應用程序都有同樣的問題。但我沒有提到任何關於死鎖的實體框架書籍。
我在這里找到了一篇關於這個的文章。 基本上聽起來您可以啟動和停止圍繞您的 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 = CreateMyContext())
{
ctx.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
// Get the user session for the client session
...
}
您可能每個會話都使用事務? 在這種情況下,它們將死鎖,因為事務在嘗試保存時都嘗試從共享鎖升級到排他鎖。 這似乎沒有得到很好的記錄,因為 EF 支持樂觀並發。
解決此問題的一種方法是使用以下內容提供更新鎖提示:
return context.TestEntities
.SqlQuery("SELECT TOP 1 Id, Value FROM TestEntities WITH (UPDLOCK)")
.Single();
}
參見: 實體框架 6 和悲觀並發
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.