首页 > 数据库 >MySQL间隙锁Gap Lock如何防止幻读?

MySQL间隙锁Gap Lock如何防止幻读?

来源:互联网 2026-07-05 11:07:11

间隙锁仅生效于可重复读隔离级别,是临键锁的组成部分,用于防止幻读。它仅在范围查询使用索引时触发,锁定索引记录间的间隙,阻止其他事务插入新行。可通过性能模式或观察插入阻塞来验证其存在。

直接给出结论:Gap Lock并非在所有场景下都能使用,它对运行环境有严格要求——必须处于REPEATABLE READ隔离级别,否则根本没有触发的机会。更准确地说,它从不单独发挥作用,而是作为Next-Key Lock的组成部分,专门针对“不存在的值”进行封锁,最终目标是防止幻读。此外,只有在范围查询且走索引时,Gap Lock才会真正生效。

下面详细拆解几个关键点。

长期稳定更新的攒劲资源: >>>点此立即查看<<<

Gap Lock仅在RR隔离级别生效,RC下完全不触发

这是第一道硬性门槛。简单来说,如果隔离级别设置为READ COMMITTED,即使执行SELECT * FROM t WHERE id > 10 FOR UPDATE,InnoDB也只会对已存在的数据行加Record Lock,行与行之间的间隙不会上锁。后果是幻读风险直接暴露:其他事务可以随时在id=15的位置插入新记录。

因此,操作前务必确认当前会话隔离级别为REPEATABLE READ。检查方法很简单:运行SELECT @@transaction_isolation;,如果返回REPEATABLE-READ,前提条件才成立。否则,Gap Lock不可用。

Gap Lock从不单独存在,它总是Next-Key Lock的一部分

在InnoDB中,不会出现“仅加Gap Lock”的操作。Gap Lock始终与Record Lock打包,形成完整的Next-Key Lock。举个例子:假设表中有id=5、10、20三行数据,执行SELECT * FROM t WHERE id > 5 FOR UPDATE,InnoDB实际会添加两个Next-Key Lock:(5,10](锁记录10及间隙(5,10))和(10,20](锁记录20及间隙(10,20)),以及一个(20,+supremum]。注意括号中的开区间才是Gap Lock真正发挥作用的区域——它的职责是阻止其他事务申请Insert Intention Lock。任何插入操作必须先获取该意向锁才能继续,Gap Lock拦截的就是这一步。

这或许有些反直觉,但正是InnoDB的设计哲学:它锁的不是“值”,而是“位置”。

没有索引或等值查询,Gap Lock不会启动

以下是几个常见但容易踩坑的场景:

  • WHERE status = 'pending':如果status字段没有建立索引,InnoDB会进行全表扫描,间隙锁完全不参与。即使有索引,等值查询搭配非唯一索引时,仍可能只加Record Lock,不覆盖前后间隙。
  • WHERE id > 10(id为主键):属于标准的走索引范围查询,条件满足,Next-Key Lock生效,锁住(10,+supremum]整个后缀区间。
  • SELECT * FROM t FOR UPDATE(无WHERE条件):这是最极端的情况——全表扫描时,InnoDB会锁住从(∞, min_key](max_key, +supremum]的全部间隙,逻辑上相当于锁住整张表。虽然操作本身允许,但并发性能会急剧下降。

验证Gap Lock是否真正生效,不能只看隔离级别

仅仅设置SET TRANSACTION ISOLATION LEVEL REPEATABLE READ还不够,需要观察锁的实际行为。最可靠的验证方式是通过performance_schema.data_locks查询:SELECT LOCK_MODE, LOCK_DATA FROM performance_schema.data_locks WHERE LOCK_TRX_ID = '你的事务ID';。如果LOCK_MODE显示为RECORD & GAPRECORD & NEXT-KEY,说明Gap部分已生效;如果只显示RECORD,则仅为行锁;如果查不到记录,很可能没有加锁。

还有一种更直观的验证方法:事务A执行SELECT * FROM t WHERE id > 5 FOR UPDATE后,让事务B立即执行INSERT INTO t VALUES (6, ...)。如果被阻塞,说明间隙确实被锁住了。

Gap Lock真正棘手的地方在于,它锁的是“不存在的值”——多个事务对同一段空隙加锁时,彼此之间互不可见。正因为看不到,一旦插入顺序不同,就可能引发死锁。更隐蔽的一点是,它只对当前读(FOR UPDATELOCK IN SHARE MODE)有效;普通SELECT走的是MVCC快照读,根本感知不到间隙锁的存在。换句话说,快照读查询到的数据看起来没问题,但其他事务可能已经向空隙中插入了数据。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。