mysql的樂觀鎖與悲觀鎖
樂觀鎖
總是認為不會產生並發問題,每次去取數據的時候總認為不會有其他線程對數據進行修改,因此不會上鎖,但是在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制或CAS操作實現。
例如:
有這樣一個表:
每次更新時update在條件後再附加一個時間為條件:
update user_info set password=‘somelog‘ where username=‘somelog‘ and time=‘2018-07-11‘;
因為如果並發操作,同一刻查詢的時間一樣,但是先插入時將時間更改,那麽後更新的操作就不能進行,因為time的值被前一個操作更改了。
這就是樂觀鎖的實現原理,更新時附加一個版本號。
悲觀鎖
總是假設最壞的情況,每次取數據時都認為其他線程會修改,所以都會加鎖(讀鎖、寫鎖、行鎖等),當其他線程想要訪問數據時,都需要阻塞掛起。可以依靠數據庫實現,如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖,在Java中,synchronized的思想也是悲觀鎖。
註:要使用數據庫的悲觀鎖,我們必須關閉mysql數據庫的自動提交屬性,因為MySQL默認使用autocommit模式,也就是說,當你執行一個更新操作後,MySQL會立刻將結果進行提交。
悲觀鎖分為兩種:共享鎖和排它鎖
共享鎖是其它事務可以讀但是不能寫
排他鎖是只有自己得事務有權限對此數據進行讀寫
SQL寫法
共享鎖(S):
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;
排他鎖(X):
SELECT * FROM table_name WHERE ... FOR UPDATE;
加鎖必須先開啟事務:begin;(開啟事務)->加鎖、操作->commit;(提交事務,歸還鎖)
加鎖分為顯式加鎖與隱式加鎖,上面的寫法是顯式加鎖。mysql在執行insert、update會自動加鎖,mysql對select卻不會加鎖。
例如:
不加鎖
select * from data where username=‘somelog’;
加排它鎖:
select * from data where username=‘somelog’ for update;
如果一個事務加了排它鎖之後,另外一個事務不加鎖的select也可以查詢到數據
以上可以看出,鎖不是針對事務的,排它鎖只有一把,誰拿了誰就可以進行更新,但是沒有拿到鎖的事務只要在select不加上排它鎖也可以查詢到數據。
mysql的樂觀鎖與悲觀鎖