InnoDB行鎖類型
- 共享鎖(S):容許一個事務去讀取一行,阻止其餘事務獲取相同數據集的排他鎖。
- 排他鎖(X):容許得到排他鎖的事務更新數據,組織其餘事務獲取相同數據集的共享鎖和排他鎖。
加鎖方式
- 共享鎖(S):select * from table_name where ... lock in share mode;
- 排他鎖(S):select * from table_name where ... for update;
for update是在數據庫中上鎖用的,能夠爲數據庫中的行上一個排它鎖。當一個事務的操做未完成時候,其餘事務能夠讀取可是不能寫入或更新。sql
for update的使用場景
若是遇到存在高併發而且對於數據的準確性頗有要求的場景,是須要了解和使用for update的。 好比涉及到金錢、庫存等。通常這些操做都是很長一串而且是開啓事務的。若是庫存剛開始讀的時候是1,而立馬另外一個進程進行了update將庫存更新爲0了,而事務尚未結束,會將錯的數據一直執行下去,就會有問題。因此須要for upate 進行數據加鎖防止高併發時候數據出錯。 ==記住一個原則:一鎖二判三更新==數據庫
InnoDB行鎖實現方式
InnoDB行鎖是經過給索引項加鎖來實現的,若是沒有索引,InnoDB將經過隱藏的聚簇索引來對記錄枷鎖。
for update如何使用
使用姿式:併發
select * from table_name where xxx for update
for update的鎖表 InnoDB默認是行級別的鎖,當有明確指定的主鍵/索引時候,是行級鎖。不然是表級別。高併發
例子: 假設表user ,表數據及結構以下。 測試
例1: (明確指定主鍵/索引,而且有此記錄,行級鎖) spa
SELECT * FROM user WHERE id = 1 FOR UPDATE;
例2: (未指定主鍵/索引,而且有此記錄,表級鎖) 3d
SELECT * FROM user WHERE name = '小明' FOR UPDATE;
例3: (當咱們使用範圍條件而不是相等條件檢索數據並請求共享鎖或排他鎖時,InnoDB會給條件已有數據記錄的索引項加鎖,對於鍵值在條件範圍但不存在的記錄加間隙鎖)code
SELECT * FROM user WHERE id > 6 FOR UPDATE;
若是查不到數據for update是否會加鎖呢?blog
例4: (明確指定主鍵/索引,若查無此記錄,加間隙鎖) 因而可知當根據主鍵/索引查詢不到數據時仍然會加鎖,這時候加的是間隙鎖加鎖區間是[4,6)索引
SELECT * FROM user WHERE id = 4 FOR UPDATE;
例5: (無主鍵/索引,表級鎖)
SELECT * FROM user WHERE name = ’小王’ FOR UPDATE;
例6: (主鍵/索引不明確,表級鎖)
SELECT * FROM user WHERE id<>’3’ FOR UPDATE; SELECT * FROM user WHERE id LIKE ‘3’ FOR UPDATE;
for update的注意點
- for update 僅適用於InnoDB,而且必須開啓事務,在begin與commit之間才生效。
- 要測試for update的鎖表狀況,能夠利用MySQL的Command Mode,開啓二個視窗來作測試。
for update的疑問點:- 當開啓一個事務進行for update的時候,另外一個事務也有for update的時候會一直等着,直到第一個事務結束嗎?
答:會的。除非第一個事務commit或者rollback或者斷開鏈接,第二個事務會立馬拿到鎖進行後面操做。不過也能夠設置鎖等待超時參數innodb_lock_wait_timeout來解決。- 若是沒查到記錄會加鎖嗎?
答:==會的。有主鍵/索引產生間隙鎖,無主鍵/索引產生表鎖表級鎖。==- for update 和 for update nowait區別(前者阻塞其餘事務,後者拒絕其餘事務) for update鎖住表或者鎖住行,只容許當前事務進行操做(讀寫),其餘事務被阻塞,直到當前事務提交或者回滾,被阻塞的事務自動執行 for update nowait 鎖住表或者鎖住行,只容許當前事務進行操做(讀寫),其餘事務被拒絕,事務佔據的statement鏈接也會被斷開