Entity Framework 開放式並行存取控制

來源:互聯網
上載者:User

標籤:style   blog   http   color   使用   os   strong   io   

一、背景  我們知道,為了防止並發而出現髒讀髒寫的情況,可以使用Lock語句關鍵字,這屬於封閉式並行存取控制的一種技術,,但在分布式網站下,鎖的作用幾乎不存在,因為雖然鎖住了A伺服器的執行個體對象,但B伺服器上的鎖是不知道的A伺服器上鎖的情況的,所以,面對分布式網站、單一資料庫這種架構,我們可以使用EntityFramework的開放式並行存取控制來解決這個問題,EF對並發控制有不管控和開放式並行存取控制兩種,預設情況是不管控,但EF不支援封閉式並行存取。
lock 確保當一個線程位於代碼的臨界區時,另一個線程不進入臨界區。如果其他線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
 二、封閉式並行存取和開放式並行存取

封閉式並行存取:比如有兩個使用者A,B,同時登入系統修改一個文檔,如果A先進入修改,則系統會把該文檔鎖住,B就沒辦法開啟了,只有等A修改完,完全退出的時候B才能進入修改。

開放式並行存取:同上面的例子,A,B兩個使用者同時登入,如果A先進入修改緊跟著B也進入了。A修改文檔的同時B也在修改。如果在A儲存之後B再儲存他的修改,此時系統檢測到資料庫中文檔記錄與B剛進入時不一致,B儲存時會拋出異常,修改失敗。

開放式並行存取的基本出發點是:當儲存資料的時候抱著一種樂觀的態度,不期望發生並發衝突,即使萬一發生並發衝突,也能捕捉到衝突異常,然後根據策略解決衝突,而解決衝突的方式一般分為Client wins(以後操作者為贏) 和 Store wins(以先儲存的資料為贏)。

 三、EF中如何控制並發第1步、  在設計器中,對需要進行並發控制的欄位的ConcurrencyMode併發模式設定為Fixed,這是檢測是否發生衝突的指標,該欄位最終會在EF產生SQL時的where子句出現,如果沒有設定為Fixed,即使該欄位出現並發衝突,EF也不會報出並發異常,從而會導致出現髒讀髒寫的情況。   第2步、 Resolving optimistic concurrency exceptions with Reload

  使用Reload資料作為解決開放式並行存取異常的策略之一,我在這裡就講資料Reload這一種策略就好了,除了Reload外,還有其他幾種衝突解決方案策略,詳見參考文獻中EF官方團隊部落格。

  微軟Entity Framework 團隊官方部落格 推薦處理開放式並行存取衝突的策略之一是Reload資料,也就是EF檢測到並發衝突時會拋出DbUpdateConcurrencyException,這時解決衝突分為Client Wins或者Store Wins ,而Reload處理也就是Store Wins,意味著放棄當前記憶體中的實體,重新到資料庫中載入當前實體,EF官方團隊給出來的範例程式碼如下,其他幾種策略請見參考文獻連結。  
using (var context = new UnicornsContext()){    bool saveFailed;    do    {        saveFailed = false;        var unicorn = context.Unicorns.Find(1);        unicorn.Name = "tom";        try        {            context.SaveChanges();        }        catch (DbUpdateConcurrencyException ex)        {            saveFailed = true;            // Update the values of the entity that failed to save             // from the store            ex.Entries.Single().Reload();        }    } while (saveFailed);}

 

四、SqlProfiler看原理

  完成以上步驟後,您的程式就具備了開放式並行存取處理的能力了,但是,其中的原理是什麼呢?從SqlProfiler監控結果來看,EF是將併發模式設定為Fixed的欄位放在where子句裡,後操作會因為取不到相應的記錄而更新失敗,打個比方說,當兩個使用者同時對同一條記錄(ID=1,Count=10)進行讀、寫操作的時候,A、B同時讀取記錄的時候,Count都等於10,A使用者先進行Update減1操作,此時(ID=1,Count=9),而此時B使用者稍微晚一點點再進行Update操作的時候,因為Count已經被A修改成9了,已經不存在(ID=1,Count=10)的記錄了,所以B最終執行影響行數為0,EntityFramework拋出並發異常:


如:我們給Count屬性的併發模式設定成Fixed的話,那產生的SQL語句如下:


exec sp_executesql N‘update [dbo].[OrderLog]set [Count] = @0where (([ID] = @1) and ([Count] = @2))‘,N‘@0 int,@1 int,@2 int‘,@0=78,@1=1,@2=9 

 

當EntityFramework執行更新操如果影響行數為0,就會拋出異常,相關原始碼如下所示:

 


 五、總結

   個人認為,開放式並行存取控制適用於並發量還不是很大情況,也就是符合開放式並行存取的初衷,當儲存資料的時候不期望發生並發衝突,一旦發生衝突,也能捕捉到衝突異常,然後根據策略解決衝突或者提示使用者操作失敗等,但是,當並發量很大的時候,我認為開放式並行存取就顯得並不那麼適用了,個人建議,做評估項目並發風險和做並發衝突的測試,假如完全可以接受,大可以應用EntityFramework的開放式並行存取控制,實現起來也比較簡單,假如項目並發量確實很大,那可以考慮別的技術方案實現,比如訊息佇列……等。

 參考文獻

(1)微軟EntityFramework團隊部落格: Using DbContext in EF 4.1 Part 9: Optimistic Concurrency Patterns

(2)Gyoung: Entity Framework 並發處理

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.