MySQL记录锁与间隙锁的区别是什么?

作者:技术拾光

时间:2026-08-18

浏览:247

记录锁用于锁定已存在的索引记录;间隙锁用于锁定两个索引值之间的空隙,以阻止新记录插入;当对非唯一索引执行等值查询时,二者会组合形成临键锁。具体加锁类型需要通过 SHOW ENGINE INNODB STATUS 确认,同时还会受到隔离级别和索引类型的影响。记录锁只锁已存在的索引记录,不锁间隙记录锁(

文章目录

记录锁用于锁定已存在的索引记录;间隙锁用于锁定两个索引值之间的空隙,以阻止新记录插入;当对非唯一索引执行等值查询时,二者会组合形成临键锁。具体加锁类型需要通过 SHOW ENGINE INNODB STATUS 确认,同时还会受到隔离级别和索引类型的影响。

MySQL记录锁与间隙锁的区别是什么?

记录锁只锁已存在的索引记录,不锁间隙

记录锁(Record Lock)是最接近“锁住某一行”的锁类型,但它实际锁定的并不是数据行本身,而是该行在聚簇索引或二级索引上的索引记录。只要查询条件能够命中索引,尤其是主键或唯一索引,并且精确匹配到已存在的记录,InnoDB 通常就只会加记录锁。

常见触发场景包括:

  • SELECT * FROM users WHERE id = 10 FOR UPDATE; —— 当 id 为主键时,会锁定对应的索引记录
  • UPDATE orders SET status = 'paid' WHERE order_no = 'ORD-2026-001'; —— 当 order_no 为唯一索引时,也只锁定对应记录

需要注意的是,如果查询没有使用索引,就可能退化为更大范围的锁;如果查询未命中任何记录,则不会加记录锁,这种情况下可能会转为间隙锁。

间隙锁只锁索引之间的空隙,用于阻止插入

间隙锁(Gap Lock)不会锁定实际存在的数据行,它锁定的是两个索引值之间的区间空隙,通常可表示为左开右开的区间,如 (10, 20)。它的核心作用是阻止其他事务在该区间内执行 INSERT,从而避免幻读。

典型触发条件包括:

  • 事务隔离级别为 REPEATABLE READ,因为在 READ COMMITTED 下默认通常不启用间隙锁
  • 查询使用了非唯一索引或范围条件,并且扫描范围覆盖了索引间隙
  • 例如:SELECT * FROM users WHERE age BETWEEN 25 AND 35 FOR UPDATE; —— 即使表中不存在 age = 28 的记录,也可能锁住 (25, 35) 这一段间隙

此外,SELECT ... FOR UPDATE、UPDATE 和 DELETE 都可能触发间隙锁,而普通的 SELECT 无锁读通常不会触发。

非唯一索引的等值查询,可能同时出现记录锁和间隙锁

在实际使用中,最容易引起误判的情况之一,就是基于非唯一索引进行等值匹配时的加锁行为。例如执行 WHERE status = 'pending' 这类条件时,InnoDB 加的往往不只是记录锁,还会同时锁住相关索引记录前后的间隙,最终形成临键锁(Next-Key Lock)。

例如:

  • 表 orders 上存在非唯一索引 idx_status(status),当前 status='pending' 对应的索引值为 20、25、30
  • 执行 SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;
  • 实际加锁范围可能包括:(15,20]、(20,25]、(25,30]、(30,35],其中假设相邻索引值分别为 15 和 35

这意味着,看似只是锁住了三条 pending 记录,实际上它们之间的空隙,以及前后相邻索引值之间的区间,也可能一并被锁定。因此,这类等值查询在高并发场景下也可能对插入操作造成明显阻塞。

确认锁类型,应查看 SHOW ENGINE INNODB STATUS

执行加锁语句后,可以在另一个会话中运行 SHOW ENGINE INNODB STATUSG,重点查看 TRANSACTIONS 段中的 RECORD LOCKS 相关内容:

  • 出现 locks rec but not gap,表示纯记录锁
  • 出现 locks gap before rec,表示间隙锁,或临键锁中的间隙部分
  • 同时出现 locks rec but not gap 和 locks gap before rec,通常可视为临键锁行为

不应仅凭 explain 或执行计划推测锁类型,真正的加锁情况仍需以 INNODB STATUS 中的锁结构描述为准。

一个容易被忽略但又非常关键的点是:间隙锁是否出现,根本上取决于事务隔离级别和索引类型,而不只是 SQL 写法本身。即使是同样的 WHERE age = 25,在 READ COMMITTED 下可能不会产生间隙锁;而在 REPEATABLE READ 下,则可能连同一整段空白区间一起锁住。因此,在正式上线前,应当在目标隔离级别下实际验证锁行为,这一步通常不能省略。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›