背景
小明和小強同時簽出了源代碼,如果小強先送出,那麼送出成功是合理的,接着小明送出了修改,這時源代碼伺服器就會告訴小明有人在他讀取之後做了修改,問他如何處理,源代碼伺服器會讓小明把修改合并後再送出。這就是樂觀鎖政策,當然源代碼服務也可以配置為悲觀鎖以避免并行修改。
合理的規避并發修改是企業應用中不能回避的問題,但現實場景是,很多團隊都回避這個問題。今天我介紹一下如何使用離線樂觀鎖處理并發修改。
相關文章:再談線上悲觀鎖、離線悲觀鎖、線上樂觀鎖和離線樂觀鎖。
思路
CAS:Compare And Swap,隻有當要修改的值在我讀取後沒有被修改,才會被交換(修改)。
CAS是多線程領域的術語,比如:無鎖的環形隊列就是基于這個實作的。因為CAS的思想和樂觀鎖的思想一緻,我就借用一下。
看一下離線樂觀鎖的應用場景:

上圖包含了如下資訊:
一、讀取線程A1和修改線程A2是不同的線程,是以才叫離線。例如:表單的讀取資料和修改。
二:CAS的Compare比較的是版本号,Swap的是整條記錄。例如:EntityFramework允許你指定哪些屬性是版本屬性。
代碼示例
設定版本字段
CAS
1 /// <summary>
2 /// 執行修改。
3 /// </summary>
4 public void Handle(TCommand command)
5 {
6 var unitOfWork = ServiceLocator.Current.GetInstance<TUnitOfWork>();
7
8 unitOfWork
9 .GetRepository<TRepository>()
10 .MarkAsModified(command.Aggregate);
11
12 unitOfWork.Commit();
13 }
運作效果
注意事項
一、示例中我直接将讀取線程讀取的資料,離線修改後傳遞個修改線程了,這樣兩個線程隻有一次讀取邏輯,這保證了CAS中Compare的正确性。有些場景你可能需要在修改線程中也進行一次讀取,然後将UI層修改的資料合并過來,這種情況就要注意了,必須要手工指定Compare操作使用第一個線程讀取的版本号,否則會使用第二次讀取的版本号。
二、樂觀離線鎖隻适合重來成本很低的場景,否則使用者編輯了兩個小時,你告訴他出現并發問題了,他會瘋的。這種成本很高的操作适合“離線悲觀鎖”。
備注
我就是一個行動跟不上思維的人,因為懶惰,我沒有全面的在項目中采用樂觀鎖,下一個項目一定全面實施。