背景
多人併發操作同一數據,可能導致數據不一致,數據不一致可是非常可怕的bug。
這是接上篇悲觀鎖講解,
樂觀悲觀鎖區別
- 併發衝突概率大的走悲觀鎖合適,概率小的走樂觀鎖
- 數據庫開銷不一樣,悲觀佔用資源多特別是長事務的情況,影響了程序的併發訪問性,樂觀鎖相反。
業務場景
工作流業務,如員工A操作工單審批通過,同時員工B也操作了相同的工單審批拒絕,
此時這個工單狀態字段可能出現不一致情況。
問題來了
- 當應用的用戶量上來了,就像今日頭條從剛開始的幾萬,到如今上億的用戶量,APP操作的響應時間越來越慢,然後老闆發話了,必須提高響應時間,讓APP操作能毫秒級響應。
- 程序汪,接到命令就開始分析代碼,發現mysql的select x for udpate 鎖,有時佔有數據庫資源非常大。提供數據庫的響應速度可是優化性能的殺手鐧啊。
解決思路
- 程序汪說幹就幹,在業務單表裡加了個lock_version字段 int類型,默認0, 0:未鎖 1:鎖住
- 先 select version from 業務單 where id=x ;
- 獲得 version的值0,如果是1,表示已經被其他人鎖了,直接退出操作或異常提示
偽代碼走起
事務 begin------
相應的業務邏輯.......
【update 業務表 set 業務值, version=version+1 where id=#{id} and version=#{version};如果更新數據影響1行,返回true 否則返回false】
更新影響1行success【加鎖OK】 ,lock_version_boolean=true 否則false【加鎖失敗】
if(!lock_version_boolean){
throw new Exception("親,你併發異常了")
}
事務 end------
finally{
最後把鎖重置 為update 0:未鎖 狀態【鎖釋放】
}
找了張圖,大家理解下
version控制
注意
- 樂觀鎖思想在SVN,GIT就得到了應用,下載代表有version,提交代碼是會更新version,當發現version不一致就提交失敗。
- 在併發量不是很大情況for update完全夠用,代碼夠簡單。悲觀鎖代碼稍微複雜點點,請根據場景正確選擇。
- 樂觀鎖說白了就一個update的sql,請注意version參數別傳錯了,添加version字段到你核心業務表中,如電影系統內容表就是核心表。
如果覺得對你有幫助請關注,有錯誤請指點,下篇繼續分析 【高性能緩存鎖】
閱讀更多 程序汪汪 的文章