悲观锁和乐观锁的区别和应用场景
悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
?
樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似于write_condition機制的其實都是提供的樂觀鎖。
?
?
?
為什么需要鎖(并發控制)?
在多用戶環境中,在同一時間可能會有多個用戶更新相同的記錄,這會產生沖突。這就是著名的并發性問題。
典型的沖突有:
l?丟失更新:一個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如:用戶A把值從6改為2,用戶B把值從2改為6,則用戶A丟失了他的更新。
l?臟讀:當一個事務讀取其它完成一半事務的記錄時,就會發生臟讀取。例如:用戶A,B看到的值都是6,用戶B把值改為2,用戶A讀到的值仍為6。
為了解決這些并發帶來的問題。 我們需要引入并發控制機制。
并發控制機制
悲觀鎖:假定會發生并發沖突,屏蔽一切可能違反數據完整性的操作。[1]
樂觀鎖:假設不會發生并發沖突,只在提交操作時檢查是否違反數據完整性。[1]?樂觀鎖不能解決臟讀的問題。
樂觀鎖應用
1.??????使用自增長的整數表示數據版本號。更新時檢查版本號是否一致,比如數據庫中數據版本為6,更新提交時version=6+1,使用該version值(=7)與數據庫version+1(=7)作比較,如果相等,則可以更新,如果不等則有可能其他程序已更新該記錄,所以返回錯誤。
2.??????使用時間戳來實現.
注:對于以上兩種方式,Hibernate自帶實現方式:在使用樂觀鎖的字段前加annotation: @Version, Hibernate在更新時自動校驗該字段。
悲觀鎖應用
需要使用數據庫的鎖機制,比如SQL SERVER 的TABLOCKX(排它表鎖)?此選項被選中時,SQL? Server? 將在整個表上置排它鎖直至該命令或事務結束。這將防止其他進程讀取或修改表中的數據。
SqlServer中使用
Begin Tran
select top 1 @TrainNo=T_NO
???????? from Train_ticket?? with (UPDLOCK)?? where S_Flag=0
????? update Train_ticket
???????? set T_Name=user,
???????????? T_Time=getdate(),
???????????? S_Flag=1
???????? where?T_NO=@TrainNo
commit
我們在查詢的時候使用了with (UPDLOCK)選項,在查詢記錄的時候我們就對記錄加上了更新鎖,表示我們即將對此記錄進行更新. 注意更新鎖和共享鎖是不沖突的,也就是其他用戶還可以查詢此表的內容,但是和更新鎖和排它鎖是沖突的.所以其他的更新用戶就會阻塞.
結論
在實際生產環境里邊,如果并發量不大且不允許臟讀,可以使用悲觀鎖解決并發問題;但如果系統的并發非常大的話,悲觀鎖定會帶來非常大的性能問題,所以我們就要選擇樂觀鎖定的方法.
?
?
兩種鎖各有優缺點,不可認為一種好于另一種,像樂觀鎖適用于寫比較少的情況下,即沖突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生沖突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
總結
以上是生活随笔為你收集整理的悲观锁和乐观锁的区别和应用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM-ICPC 2018 徐州赛区网络
- 下一篇: 第k短路 (A*算法)