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