1. 程式人生 > >樂觀鎖、悲觀鎖處理併發

樂觀鎖、悲觀鎖處理併發

處理併發問題,我們可以從2個層面去解決(這裡我只做簡單的介紹,方便理解記憶):

1.程式碼層面

常用的就是synchronize同步、ThreadLocal本地複製,這裡不過多解釋

2.資料庫層面

2.1:悲觀鎖

假設一PersonA要對某條資料進行修改,那麼查詢這條資料修改這條資料,可以對這條資料進行加鎖,sqlA(CMD視窗1):

begin;

select * from table where id = 1 for update;

update update table xx='AA' where id = 1;

commit;//在此之前,其他地方的程式碼,將不能修改id=1這條資料

PersonB也要對id=1的這條資料進行update,那麼sqlB(CMD視窗2): update table xx='BB' where id = 1;

如果sqlA還沒有執行commit;語句,那麼sqlB是不能執行成功的。因為sqlA把id=1的這條資料進行了加鎖。

只有等待sqlA執行了commit;提交事務語句,sqlB才能成功執行。

即:本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。 

悲觀鎖存在的問題:如果這個事務整體中,需要花費大量的時間處理業務邏輯再commit;那麼久意味著這段時間內,這條資料都處於加鎖狀態,其他業務邏輯或者其他系統將無法對這條資料進行操作。

那如何解決這個問題呢?答案:樂觀鎖

2.2:樂觀鎖

樂觀鎖策略:提交版本必須大於記 錄當前版本才能執行更新 

原理:需要在表中新增version欄位,每次需要修改資料之前,查詢資料的時候需要把這個version查詢出來,修改好其他屬性值,執行update之前,修改version值(version+1)。如果滿足修改後的version大於資料庫的version,再執行update。

比如:update table set name = 'xxx' and version = (修改後的version) where id = 1 and version < 修改後的version

舉例:

1.操作員A得到一條資料{id:1,value:100,version:1},開始在頁面上進行編輯操作,version=version+1 = 2,也就是改成了{id:1,value:50,version:2},

2.操作員A在提交本次修改之前,操作員B得到的資料依然是{id:1,value:100,version:1},開始在頁面上進行編輯操作,version=version+1 = 2(version也是等於2),改成了{id:1,value:150,version:2},

3.操作員B提交修改操作之前,操作員A提交事務,A的提交版本(值=2) > 資料庫version值1,滿足條件,提交成功,這時資料庫資料就是{id:1,value:50,version:2},那現在操作員B提交事務,B的提交版本(值=2) > 資料庫version值1,不成立,不執行提交。

由此可見:樂觀鎖機制避免了髒資料的產生,同時避免了長事務中的資料庫加鎖開銷。

 

更多詳細的描述建議檢視:https://www.cnblogs.com/sheseido/p/5038562.html

如果需要在web應用中用程式碼或者配置體現出來,建議執行上網查詢