樂觀鎖 -業務判斷 解決高併發問題

     在解決高併發問題時,若是是分佈式系統顯然咱們只可以使用數據庫端加鎖機制來解決這個問題,可是這種同步機制或者數據庫物理鎖機制會犧牲一部分的性能,因此經常以另一種方式來解決這個問題 就是樂觀鎖模式數據庫

  銀行兩操做員同時操做同一帳戶就是典型的樂觀鎖模式。
      好比A、B操做員同時讀取一餘額爲1000元的帳戶,A操做員爲該帳戶增長100元,B操做員同時爲該帳戶扣除50元,A先提交,B後提交。最後實際帳戶餘額爲1000-50=950元,但本該爲1000+100-50=1050。這就是典型的併發問題。併發

      樂觀鎖機制在必定程度上解決了這個問題。樂觀鎖,大可能是基於數據版本(Version)記錄機制實現。何謂數據版本?即爲數據增長一個版本標識,在基於數據庫表的版本解決方案中,通常是經過爲數據庫表增長一個 「version」 字段來實現。框架

  讀取出數據時,將此版本號一同讀出,以後更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,若是提交的數據版本號大於數據庫表當前版本號,則予以更新,不然認爲是過時數據。分佈式

  對於上面修改用戶賬戶信息的例子而言,假設數據庫中賬戶信息表中有一個version字段,當前值爲1;而當前賬戶餘額字段(balance)爲1000元。假設操做員A先更新完,操做員B後更新。
a、操做員A此時將其讀出(version=1),並從其賬戶餘額中增長100(1000+100=1100)。
b、在操做員A操做的過程當中,操做員B也讀入此用戶信息(version=1),並從其賬戶餘額中扣除50(1000-50=950)。
c、操做員A完成了修改工做,將數據版本號加一(version=2),連同賬戶增長後餘額(balance=1100),提交至數據庫更新,此時因爲提交數據版本大於數據庫記錄當前版本,數據被更新,數據庫記錄version更新爲2。
d、操做員B完成了操做,也將版本號加一(version=2)試圖向數據庫提交數據(balance=950),但此時比對數據庫記錄版本時發現,操做員B提交的數據版本號爲2,數據庫記錄當前版本也爲2,不知足 「提交版本必須大於記錄當前版本才能執行更新 「的樂觀鎖策略,所以,操做員B的提交被駁回。
這樣,就避免了操做員B用基於version=1的舊數據修改的結果覆蓋操做員A的操做結果的可能。高併發

操做員A操做以下:性能

select id, balance, version from account where id="1"; 
查詢結果:id=1, balance=1000, version=1

update account 
set balance=balance+100, version=version+1 
where id="1" and version=1

select id, balance, version from account where id="1"; 
查詢結果:id=1, balance=1100, version=2

 

操做員B操做以下:spa

select id, balance, version from account where id="1"; 
查詢結果:id=1, balance=1000, version=1

#操做員A已修改爲功,實際account.balance=1100、account.version=2,操做員B也將版本號加一(version=2)試圖向數據庫提交數據(balance=950),但此時比對數據庫記錄版本時發現,操做員B提交的數據版本號爲2,數據庫記錄當前版本也爲2,不知足 「提交版本必須大於記錄當前版本才能執行更新 「的樂觀鎖策略,所以,操做員B的提交被駁回。
update account 
set balance=balance-50, version=version+1 
where id="1" and version=1 

select id, balance, version from account where id="1"; 
查詢結果:id=1, balance=1100, version=2

 

  Hibernate、JPA等ORM框架或者實現,是使用版本號,再判斷UPDATE後返回的數值code

相關文章
相關標籤/搜索