樂觀鎖、悲觀鎖處理併發
處理併發問題,我們可以從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應用中用程式碼或者配置體現出來,建議執行上網查詢