最近項目上線試運作過程中,總是遇到各種莫名其妙的問題,糾結了很久,今天就ef出現的“不允許啟動新事務,因為有其他線程正在該會話中運作”這個錯誤,記錄自己的解決方法。
當遇到這個問題的時候,在網上搜了很久,在這裡還是要鄙視一下那些轉載又不寫出處的站長。
問題發現:
開始一直以為是資料庫或者伺服器的問題,因為用的是虛拟空間,很多設定沒有辦法改變。後來加入站長統計之後,發現pv量居然在200左右,突然意識到有可能是并發造成的。于是自己寫了一段測試代碼,該段代碼的作用是模拟使用者閱讀新聞的時候,使新聞的閱讀次數加1(隻是改變字段的值,而不是新增一條浏覽記錄再去統計閱讀次數)。代碼如下:
public partial class WebForm1 : System.Web.UI.Page
{
delegate bool MyDelegate(Read info);
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
ReadInfo ri = new ReadInfo ();
Read rad1 = ri.Get(1);
rad1.ReadTime += 1;
Read rad2 = ri.Get(1);
rad2.ReadTime += 1;
MyDelegate myDelegate = new MyDelegate(ri.Update);
myDelegate.BeginInvoke(rad1, null, null);
myDelegate.BeginInvoke(rad2, null, null);
Thread.Sleep(300);
}
}
}
public class ReadInfo
{
testEntities mytest = new testEntities();
public ReadInfo()
{
mytest.Read.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;
mytest.Read.EnablePlanCaching = false;
}
public Read Get(int Id)
{
return mytest.Read.SingleOrDefault(c => c.myId == Id);
}
public bool Update(Read Info)
{
int Result = 0;
if (mytest.Read.Count(c => c.myId == Info.myId) == 1)
{
Thread.Sleep(100);
Result = mytest.SaveChanges();
}
return Result > 0;
}
}
F10跟蹤代碼運作就報以下錯誤:
于是監控以下代碼發現并發産生的時候,第一次是Modified,第二次卻是Unchanged,是以當運作第二次更新的時候,則報錯“不允許啟動新事務,因為有其他線程正在該會話中運作”
是以最後解決此問題的方法就是将Update的代碼改成:
public bool Update(Read Info)
{
int Result = 0;
if (mytest.Read.Count(c => c.myId == Info.myId) == 1)
{
if (Info.EntityState == System.Data.EntityState.Modified)
{
mytest.Refresh(RefreshMode.ClientWins, Info);
Thread.Sleep(100);
Result = mytest.SaveChanges();
}
}
return Result > 0;
}
雖然這樣解決可以保證程式的穩定性,但是當并發發生的時候,閱讀次數就不能+1了。不過閱讀次數這個屬性對于網站的資料而言并不是很重要,是以先這麼解決着吧。如果是比較重要的屬性,建議還是通過add方法去增加記錄,而不是修改記錄。或者通過用存儲過程,将資料重新刷進表中,但是這樣就缺乏實時性。
真是蛋痛的并發!以後再想想,看看有沒有其他的解決辦法吧。