不允許啓動新事務,因爲有其他線程正在該會話中運行(ef併發錯誤處理之一)

最近項目上線試運行過程中,總是遇到各種莫名其妙的問題,糾結了很久,今天就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方法去增加記錄,而不是修改記錄。或者通過用存儲過程,將數據重新刷進表中,但是這樣就缺乏實時性。


真是蛋痛的併發!以後再想想,看看有沒有其他的解決辦法吧。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章