樂觀鎖和悲觀鎖都是一種思想,並不是真實存在於資料庫中的一種機制。
當認為資料被併發修改的機率比較大,需要在修改之前借助於資料庫鎖機制,先對資料進行加鎖的思想被稱為悲觀鎖,又稱pcc(pessimistic concurrency control)。在效率方面,處理鎖的操作會產生了額外的開銷,而且增加了死鎖的機會。當乙個執行緒在處理某行資料的時候,其它執行緒只能等待。
悲觀鎖的實現是依賴於資料庫提供的鎖機制,流程如下:
1.修改記錄前,對記錄加上排他鎖(exclusive locking)
2.如果加鎖失敗,說明這條資料正在被修改,那麼當前查詢要等待或者丟擲異常,這由開發者決定
3.如果加鎖成功,可以對這條資料修改了,事務完成解鎖
4.加鎖修改期間,其他事務也想對這條記錄進行操作時,都要等待或者直接丟擲異常
在使用mysql innodb引擎實現悲觀鎖時,必須關閉mysql的自動提交屬性,因為mysql預設使用autocommit模式,也就是說,當你執行乙個更新操作後,mysql會立刻將結果進行提交。set autocommit=0;
舉例說明下單扣減庫存如何使用悲觀鎖實現
//0.開始事務
begin;
//1.查詢出商品庫存資訊
select quantity from items where id=1 for update;
//2.修改商品庫存為2
update items set quantity=2 where id = 1;
//3.提交事務
commit;
使用select…for update會把資料鎖住。mysql innodb預設行級鎖,行級鎖都是基於索引的,如果一條sql語句用不到索引是不會使用行級鎖的,會使用表級鎖把整張表鎖住,這點需要注意
樂觀鎖思想認為,資料一般是不會造成衝突的。只有在提交資料的時候,才會對資料的衝突進行檢測。當發現衝突的時候,返回錯誤的資訊,讓使用者決定如何去做。
樂觀鎖不會使用資料庫提供的鎖機制,一般的實現方式就是記錄資料版本。
樂觀鎖的實現不需要借助於資料庫鎖機制,只要就是兩個步驟:衝突檢測和資料更新,其中一種典型的是實現方法就是cas(compare and swap)
cas實現樂觀鎖
cas是一種樂觀鎖實現方式,顧名思義就是先比較後更新。在對乙個資料進行更新前,先持有對這個資料原有值的備份。比如,要將a=2更新為a=3,在進行更新前會比較此刻a是否為2.如果是2,才會進行更新操作。當多個執行緒嘗試使用cas同時更新乙個變數時,只有乙個執行緒能夠成功,其餘都是失敗。失敗的執行緒不會被掛起,而是被告知這次競爭失敗,並且可以再次嘗試。
比如前面的扣減庫存問題,樂觀鎖方式實現如下:
//查詢出商品庫存資訊,quantity = 3
select quantity from items where id=1
//修改商品庫存為2
update items set quantity=2 where id=1 and quantity = 3;
在更新之前,先查詢庫存表中當前庫存數,然後在做update時,以庫存數作為乙個修改條件。當進行提交更新的時候,判斷資料庫的當前庫存數與第一次取出來的庫存數進行比對,相等則更新,否則認為是過期資料。
但是這種更新存在乙個比較嚴重的問題,即aba問題。
aba問題
a執行緒去除庫存數3,b執行緒取出庫存數3,b執行緒先將庫存數變為2,又將庫存數變為3,a執行緒在進行更新操作時發現庫存是仍然是3,然後操作成功。儘管a執行緒操作是成功的,但是不能代表這個過程就是沒問題的
解決aba問題的乙個方法是通過乙個順序遞增的version欄位:
//查詢出商品資訊,version = 1
select version from items where id=1
//修改商品庫存為2
update items set quantity=2,version = 2 where id=1 and version = 1;
在每次執行資料的修改操作時,都會帶上乙個版本號,一旦版本號和資料版本號一致就可以執行修改操作並對版本號執行+1操作,否則執行失敗。因為每次修改操作都會將版本號增加,所以不會出現aba問題。還可以使用時間戳,因為時間戳天然具有順序遞增性。
##樂觀鎖和悲觀鎖對比
樂觀鎖並不是真正的加鎖,優點是效率高,缺點是更新失敗的概率比較高;悲觀鎖依賴於資料庫鎖機制,更新失敗的概率比較低,但是效率也低。
樂觀鎖和悲觀鎖
1 悲觀鎖,正如其名,它指的是對資料被外界 包括本系統當前的其他事務,以及來自外部系統的事務處理 修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制 也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無...
樂觀鎖和悲觀鎖
併發衝突 在多使用者的環境下,如果使用者同時修改同乙個文件,就會造成衝突。典型的衝突有兩種 1 丟失更新 乙個使用者的更新記錄覆蓋了另乙個人的更新。如 使用者一 讀 寫 使用者二 讀 寫 那麼使用者一就把使用者二的更新覆蓋了。2 髒讀 乙個使用者更新資料未完成時,另乙個使用者就讀取資訊。使用者一 讀...
樂觀鎖和悲觀鎖
為什麼需要鎖 併發控制 在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 l 丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。l 髒讀...