MySQL for update使用詳解
InnoDB行鎖類型
- 共享鎖(S):允許一個事務去讀取一行,阻止其他事務獲取相同數據集的排他鎖。
- 排他鎖(X):允許獲得排他鎖的事務更新數據,組織其他事務獲取相同數據集的共享鎖和排他鎖。
加鎖方式
- 共享鎖(S):select * from table_name where ... lock in share mode;
- 排他鎖(S):select * from table_name where ... for update;
for update是在數據庫中上鎖用的,可以為數據庫中的行上一個排它鎖。當一個事務的操作未完成時候,其他事務可以讀取但是不能寫入或更新。
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: (明確指定主鍵/索引,並且有此記錄,行級鎖)
SELECT * FROM user WHERE id = 1 FOR UPDATE;
例2: (未指定主鍵/索引,並且有此記錄,表級鎖)
SELECT * FROM user WHERE name = '小明' FOR UPDATE;
例3: (當我們使用范圍條件而不是相等條件檢索數據並請求共享鎖或排他鎖時,InnoDB會給條件已有數據記錄的索引項加鎖,對於鍵值在條件范圍但不存在的記錄加間隙鎖)
SELECT * FROM user WHERE id > 6 FOR UPDATE;
如果查不到數據for update是否會加鎖呢?
例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連接也會被斷開- https://www.cnblogs.com/xiao-lei/p/12598552.html