

新闻资讯
技术学院间隙锁是InnoDB在REPEATABLE READ级别下锁定索引中两值间空档(如(5,10))以防止幻读的机制,仅对范围查询或非唯一索引等值未命中时触发,不阻塞其他间隙锁但会阻塞插入。
间隙锁(Gap Lock)不是锁某一行,而是锁住索引中两个值之间的“空档”——比如现有记录 id = 5 和 id = 10,那 (5, 10) 这个开区间就被锁住了,别人不能往里插 id = 7 或 id = 8 的新行。它只在 REPEATABLE READ 隔离级别下生效,核心目的就一个:堵住幻读的漏洞。
不是所有 SELECT ... FOR UPDATE 都会加间隙锁,得看查询条件和索引结构:
SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE,会锁住所有命中范围的记录 + 它们之间的间隙 + 边界外的间隙(如 (5, 10)、(10, 20)、(20, 25))WHERE c = 7,而表里 c 字段只有 5 和 10,那就会锁 (5, 10)
RECORD LOCK(行锁),不加间隙锁
READ COMMITTED 级别下,间隙锁被完全禁用,所以不会出现因间隙锁导致的插入阻塞常见现象是:事务 A 执行了带锁的范围查询,事务 B 突然
发现 INSERT 卡住不动,SHOW PROCESSLIST 显示 update 或 insert 状态为 Locked,但查不到显式锁表语句。这时可以:
SELECT * FROM performance_schema.data_locks;关注
LOCK_MODE 列:若看到 X,GAP 就是间隙锁,X,REC_NOT_GAP 是纯行锁,X(无后缀)通常是 Next-Key Lock
SELECT @@transaction_isolation;必须是
REPEATABLE-READ 才可能触发EXPLAIN SELECT * FROM t WHERE c BETWEEN 10 AND 20 FOR UPDATE;如果
type 是 ALL(全表扫描),InnoDB 可能退化为锁整个索引范围,甚至升级成表锁它不冲突、不互斥,但副作用很强:
Gap Lock 不会阻塞彼此,但只要有一个事务在该间隙内尝试 INSERT,就会被全部卡住 —— 表面看没锁竞争,实际是“静默阻塞”(max_id, +∞),导致后续所有 INSERT 都被拦住,尤其在分页写入或批量导入时很隐蔽WHERE status = 'pending'(非唯一索引)后直接 INSERT,却因间隙锁失败,日志里只报超时,不报死锁data_locks 实测真正难的不是理解间隙锁,而是它总在你没意识到的地方悄悄起作用——尤其是当你的查询看似“只读”,却用了 FOR UPDATE 或走的是非唯一索引时。