MySQL行鎖、間隙鎖和臨鍵鎖示例詳解
在MySQL中,InnoDB存儲引擎實現了其自己的多版本并發(fā)控制(MVCC)機制,以及基于鎖的并發(fā)控制。InnoDB使用鎖來實現事務的隔離級別,其中包括行鎖(Row Locks)、間隙鎖(Gap Locks)和臨鍵鎖(Next-Key Locks)。這些鎖的類型對于理解事務的隔離級別和避免死鎖等問題非常重要。
1.行鎖 (Record Lock)
鎖住索引中的一條具體記錄。 保證原子性:防止多個事務同時修改同一條記錄
例如:SELECT * FROM t WHERE id = 10 FOR UPDATE;會在 id=10這條記錄的索引上加行鎖。
示例
-- 事務A BEGIN; SELECT * FROM users WHERE id = 10 FOR UPDATE; -- 此時其他事務執(zhí)行以下操作會被阻塞: -- UPDATE users SET name = 'new' WHERE id = 10; -- DELETE FROM users WHERE id = 10;
2.間隙鎖(Gap Lock)
鎖住索引記錄之間的間隙,但不包括記錄本身。唯一目的就是防止其他事務在這個間隙中插入新記錄,解決幻讀問題。
它是一個開區(qū)間。例如:假設表中有 id為 5, 10, 15 的記錄。那么間隙鎖可以鎖住 (-∞, 5),(5, 10),(10, 15),(15, +∞)這些范圍。
觸發(fā)時機
(1)在可重復讀或串行化隔離級別下。
(2)唯一索引/普通索引,等值查詢,記錄不存在時。
示例
表 user,其 age字段上有普通索引

事務A: BEGIN; SELECT * FROM user WHERE age = 25 FOR UPDATE; 由于 age=25不存在,InnoDB 會找到 25所在的間隙,即 (20, 30)。此時,事務 A 會在 (20, 30)這個間隙上加間隙鎖。 事務B: INSERT INTO user (id, age) VALUES (10, 22); -- 阻塞。因為 22 在 (20, 30) 區(qū)間內 INSERT INTO user (id, age) VALUES (10, 28); -- 阻塞。因為 28 在 (20, 30) 區(qū)間內 INSERT INTO user (id, age) VALUES (10, 20); -- 成功。20 是已存在的記錄,不在間隙鎖范圍內(但可能被記錄鎖或臨鍵鎖影響) INSERT INTO user (id, age) VALUES (10, 30); -- 成功。30 是已存在的記錄,不在間隙鎖范圍內 事務 B 的插入操作會被阻塞,直到事務 A 提交。這樣就防止了在事務 A 中如果再次執(zhí)行 SELECT ... FOR UPDATE可能會看到新插入的 age=22或 28的記錄(幻讀)。
3.臨鍵鎖(Next-Key Lock)
行鎖 + 間隙鎖。它鎖住一條記錄和該記錄之前的間隙。它是一個左開右閉區(qū)間。臨鍵鎖是 InnoDB 默認的行鎖模式
例如:對于記錄 id=10,它的臨鍵鎖會鎖住 (5, 10]這個區(qū)間。這意味著既不能插入 id=6的新記錄(間隙被鎖),也不能修改或刪除 id=10的記錄(記錄被鎖)。
示例
(1)等值查詢
事務A SELECT * FROM users WHERE age = 20 FOR UPDATE;
過程:InnoDB 通過 B+ 樹找到 age=20 的記錄,并給它加上臨鍵鎖。
鎖定的范圍:(10, 20]。
為什么不是 [20, 20]?因為臨鍵鎖的本質是鎖“下一個鍵”之前的間隙。對于 age=20,它會鎖住 (上一個記錄的值, 20],即 (10, 20]。
(2)范圍查詢
事務A SELECT * FROM users WHERE age BETWEEN 15 AND 25 FOR UPDATE;
找到第一條滿足條件的記錄,即 age=20。鎖住 (10, 20]。
繼續(xù)向后掃描,找到 age=30。雖然 30 不滿足條件(30 > 25),但根據規(guī)則,掃描到的記錄也要加鎖。鎖住 (20, 30]。
最終鎖定的范圍:(10, 20] 和 (20, 30]。這相當于鎖定了整個 (10, 30] 的區(qū)間。
效果:任何試圖在 age=15 到 age=30 之間插入、更新記錄的操作都會被阻塞。
(3)特殊場景:唯一索引等值查詢
當使用唯一索引進行等值查詢并且數據存在時,InnoDB 會優(yōu)化,降級為僅使用行鎖。
SELECT * FROM users WHERE id = 3 FOR UPDATE;
此時,InnoDB 知道 id=3 是唯一的,不需要防止幻讀,所以只會鎖住 id=3 這一條記錄本身,而不會加間隙鎖。
相關SQL語句
-- 查看當前鎖信息 SELECT * FROM information_schema.INNODB_LOCKS; SELECT * FROM information_schema.INNODB_LOCK_WAITS; -- MySQL 8.0+ 性能schema鎖監(jiān)控 SELECT * FROM performance_schema.data_locks; SELECT * FROM performance_schema.data_lock_waits;
到此這篇關于MySQL行鎖、間隙鎖和臨鍵鎖示例詳解的文章就介紹到這了,更多相關mysql行鎖,間隙鎖和臨鍵鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MySQL Innodb 存儲結構 和 存儲Null值 用法詳解
這篇文章主要介紹了MySQL Innodb 存儲結構 和 存儲Null值 用法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
MySQL9.0的兩種部署模式及各個版本發(fā)布的新功能
本文主要介紹了MySQL9.0的兩種部署模式及各個版本發(fā)布的新功能,文中通過圖文示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-08-08
一道MySQL筆試題:輸出?100?以內質數(附兩種主要方法)
質數又稱素數,一個大于1的自然數,除了1和它自身外,不能被其他自然數整除的數叫做質數,這篇文章主要介紹了MySQL筆試題之輸出100以內質數的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2025-08-08

