在 InnoDB 索引結構中,Gap(間隙)指可插入新記錄的空隙。Gap Lock 即加在間隙上的鎖;Next-Key Lock 則是「記錄鎖 + 該記錄前的間隙鎖」組合。
InnoDB 採用 Next-Key Locking 算法:鎖定掃描範圍內的索引記錄,同時封鎖範圍前的間隙,使其他事務無法在間隙插入新紀錄(插入時需獲取 Insert Intention Lock),從而在 REPEATABLE READ 隔離級別下避免幻讀。
僅在 REPEATABLE READ 或 SERIALIZABLE 隔離級別下的特定操作:
SELECT ... FOR UPDATE / LOCK IN SHARE MODE)唯一索引 + 唯一條件僅鎖記錄本身,不鎖間隙。
表 tb2(id, c1),索引 tb2_idx1(id),資料:10、20、30。
BEGIN;
UPDATE tb2 SET c1=2 WHERE id=20;
INSERT INTO tb2 VALUES (9,4); -- 成功(間隙 (-∞,10))
INSERT INTO tb2 VALUES (10,4); -- 阻塞
INSERT INTO tb2 VALUES (19,4); -- 阻塞
INSERT INTO tb2 VALUES (20,4); -- 阻塞
INSERT INTO tb2 VALUES (21,4); -- 阻塞
INSERT INTO tb2 VALUES (29,4); -- 阻塞
INSERT INTO tb2 VALUES (30,4); -- 成功(間隙 [30,+∞))
被鎖定範圍為 [10, 30),即 Next-Key Lock 覆蓋區間。
UPDATE tb2 SET c1=4 WHERE id=10; -- 成功
UPDATE tb2 SET c1=4 WHERE id=20; -- 阻塞(記錄鎖衝突)
UPDATE tb2 SET c1=4 WHERE id=30; -- 成功
更新不獲取間隙鎖,僅阻塞同一記錄。
| 隔離級別 | Gap Lock 行為 |
|---|---|
| READ COMMITTED | 不加間隙鎖,允許自由插入 |
| REPEATABLE READ | 範圍查詢加 Gap/Next-Key Lock |
| SERIALIZABLE | 隱式將純 SELECT 轉為 LOCK IN SHARE MODE,同 RR |
注意:RR 下 UPDATE 會看到並發提交的修改,違反嚴格可重複讀語義,應用層需留意。
RC 下掃描不匹配記錄會釋放鎖(semi-consistent read);RR 則全程持有,對全表掃描 UPDATE 影響極大。詳細參考 何登成專欄。