asp.net core ef core mysql 新增數據並發異常處理


---------------------------------------------------------最新更新------------------------------------------------------------------

經實驗,新增出現並發異常的,是由於表中字段設置默認值的引起的。具體原因請看EF生成的sql代碼。

請看異常發生前,ef所執行的sql語句。

在insert 數據成功后,又執行了一個查詢語句,所返回的,正是表中設置默認值的字段。

這就是導致新增數據出現並發的原因。

原因如下:

ef追蹤管理實體狀態時,假設有個字段type設置有hasDefaultValue(),當前的type字段是沒有任何值的,臂如是null。

當向數據inset數據時,數據庫字段設置有默認值是“t”,數據庫會將type值null轉換為字段默認值t。

這種情況下,會出現ef管理的實體值與數據庫數據值不一致。

ef core 會將默認值查出來,返回程序中,重新賦值給ef管理的實體,

在新增的事務尚未結束時,又重新對ef管理的數據有默認值的字段進行修改賦值,就導致了新增數據出現並發的異常。

------------------------------------------我是分割線--------------------------------------------------------------------------------------

net core 2.0發布后,一直想體驗下,因種種原因,一直在拖着沒進行。

前陣子公司要加個新的內部管理后台,正好可以用asp.net core來做下,體驗下net core的魅力。

啃過文檔后就上手了,一切很順利。

直到周五,出現了一個並發異常的問題,本以為可以很快處理掉的,但沒想到一直花費了很長時間才解決掉,現在記錄下情況,有相同經歷的伙伴以后可以參考。

先上異常截圖。

並發異常

異常提示:

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See

http://go.microsoft.com/fwlink/?LinkId=527962

for information on understanding and handling optimistic concurrency exceptions.

再上代碼

 public int Add(BannerView bannerView)
        {
            try
            {

                //sysBanner.ImgUrl = sysBanner.ImgUrl.Contains("http") ? sysBanner.ImgUrl : _programConfig.AliYunOSSUrl + sysBanner.ImgUrl;
                //sysBanner.CreateDate = DateTime.Now;
                _banner.Add(new SysBanner {
                    Content = bannerView.Content,
                    CreateDate = DateTime.Now,
                    Del = (int)bannerView.Del,
                    ImgUrl = bannerView.ImgUrl.Contains("http") ? bannerView.ImgUrl : _programConfig.AliYunOSSUrl + bannerView.ImgUrl,
                    Operation = "",
                    Sort = bannerView.Sort,
                    SrcUrl = bannerView.SrcUrl,
                    Title = bannerView.Title,
                    Type = (int)bannerView.Type,
                    //MaterialId = 0,
                    //Parameter = 0,
                    //ShareType = 0
                });
                return  _banner.SaveChanges();
                
            }
            catch (DBConcurrencyException ex)
            {
                throw;
            }
        }

  

        /// <summary>
        /// 新增一條數據
        /// </summary>
        /// <param name="model"></param>
        public void Add(TEntity model)
        {
            var entity=_dbSet.Add(model);
        }


       public int SaveChanges()
        {
            return _dbContext.SaveChanges();
        }        

代碼特別簡單,就是新增一條數據,進行保存,完全沒復雜的東西。

出現並發異常,整個人是蒙逼狀態。

單人進行調試,新增一條數據,自增ID,不存在多用戶同時操作,怎么可能出現並發?

即使出現並發,主鍵也是自增ID,只會出現多條數據,也不可能是並發異常……並且多個業務模塊,其他模塊的新增完全是正常的。

這又是為什么!!!!

 

首先就是審視代碼,確定沒問題……檢查依賴注入,沒有問題……檢查ef生成的sql,沒有問題……閱讀官方文檔,沒找到原因……去群里向各位朋友請教,還是無法解決。

官方文檔有一個DBConcurrencyException處理並發異常的,是基於修改和更新的,經試驗,無法解決。

一步一步調試,源碼調試,找到幾處疑點,經排查都不是引起新增並發的bug。

重新dbfrist生成model實體,無法解決……刪除表,重建表,無法解決。

似乎走進了死胡同,園子里博問發貼,也沒有解決。整個排除過程,說起來都是淚。

后來就在想,既然底層調用方法都是一樣的,那唯一不一樣的就是存儲的實體,會不會是表結構導致的?

經過對比出現異常的表與正常的表結構,發現一個不同點,里面有幾個字段設置了默認值,還有兩個非null字段,而正常操作的那些實體里是沒有的。

嘗試取消默認值后,再注釋掉dbFirst生成的一行代碼HasDefaultValueSql("xxx"),再一運行,居然成功了!!!

 

難道是ef core mysql的bug?表不能設置默認值?這似乎不合道理,產品發布這么久了,很多人已經用在生產環境了,不可能出現這么低級的錯誤吧?

在園子里博問發貼時,有位園友向我說,默認值的字段,要加.HasDefaultValue()。這種是code first時加的,而我用dbFirst時自動生成的是HasDefaultValueSql("xxx")。

難道是調用函數不同而產生的bug?

 

 

經過多次實際測試,數據庫設置默認值及非null字段是沒有問題的。

問題出在db first生成實體時時自動加的這行代碼上HasDefaultValueSql("xxx"),只需要注釋掉這些代碼,運行就正常。

.HasDefaultValue()一樣會引起新增並發異常,原因未知。

asp.net core 2.0 

ef core mysql 

pomelo.entityFrameworkCore.mySql

如果有朋友遇到類似問題,可以做為參考。

至於為什么不能用HasDefaultValueSql("xxx")及.HasDefaultValue(),目前正在研究中,有新發現,會更新文章。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM