一、概念上的區別
樂觀鎖( Optimistic Locking):顧名思義,對加鎖持有一種樂觀的態度,即先進行業務操作,不到最后一步不進行加鎖,"樂觀"的認為加鎖一定會成功的,在最后一步更新數據的時候再進行加鎖。
悲觀鎖(Pessimistic Lock):正如其名字一樣,悲觀鎖對數據加鎖持有一種悲觀的態度。因此,在整個數據處理過程中,將數據處於鎖定狀態。悲觀鎖的實現,往往依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。
二、實現方式
樂觀鎖:
version方式:一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛才讀取到的version值為當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。
sql實現代碼:
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
CAS操作方式:即compare and swap 或者 compare and set,
涉及到三個操作數,數據所在的內存值,預期值,新值。當需要更新時,判斷當前內存值與之前
取到的值是否相等,若相等,則用新值更新,若失敗則重試,一般情況下是一個自旋操作,即不
斷的重試。
悲觀鎖:
是由數據庫自己實現的,要用的時候,我們直接調用數據庫的相關語句就可以了(原理:共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉讓給其它線程),如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖,在Java中,synchronized的思想也是悲觀鎖。
三、使用場景
樂觀鎖:
比較適合讀取操作比較頻繁的場景,如果出現大量的寫入操作,數據發生沖突的可能性就會增大,為了保證數據的一致性,應用層需要不斷的重新獲取數據,這樣會增加大量的查詢操作,降低了系統的吞吐量。
悲觀鎖:
比較適合寫入操作比較頻繁的場景,如果出現大量的讀取操作,每次讀取的時候都會進行加鎖,這樣會增加大量的鎖的開銷,降低了系統的吞吐量。
四、特點
樂觀鎖:
樂觀鎖的特點先進行業務操作,不到萬不得已不去拿鎖。即“樂觀”的認為拿鎖多半是會成功的,因此在進行完業務操作需要實際更新數據的最后一步再去拿一下鎖就好。
悲觀鎖:
悲觀鎖的特點是先獲取鎖,再進行業務操作,即“悲觀”的認為獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進行業務操作。通常所說的“一鎖二查三更新”即指的是使用悲觀鎖。
簡而言之記得一句話:讀取頻繁使用樂觀鎖,寫入頻繁使用悲觀鎖。樂觀鎖不能解決臟讀的問題。