最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
MySQL中的间隙锁Gap Lock怎样防止幻读
时间:2026-07-03 11:11:46 编辑:袖梨 来源:一聚教程网
Gap Lock仅在REPEATABLE READ隔离级别下生效,RC级别下不触发;它从不单独存在,而是作为Next-Key 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从不单独存在,它总是Next-Key Lock的一部分
你不会看到InnoDB“只加Gap Lock”,它总和Record 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压根不启动
-
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 & GAP或RECORD & NEXT-KEY,说明Gap部分已生效;若只有RECORD,那只是行锁;若查不到记录,很可能根本没加锁。另一个快速验证法:事务A执行SELECT * FROM t WHERE id > 5 FOR UPDATE后,事务B立刻执行INSERT INTO t VALUES (6, ...)——被阻塞就证明间隙真被锁住了。
Gap Lock真正难缠的地方在于它锁的是“不存在的值”,多个事务对同一段空隙加锁时互不可见,却可能因插入顺序不同引发死锁;更隐蔽的是,它只响应当前读(FOR UPDATE/LOCK IN SHARE MODE),普通SELECT靠MVCC快照读,根本感知不到间隙是否存在。
相关文章
- 刀剑缭乱2026公测兑换码大全一览 07-05
- 崩坏星穹铁道4.0卡池7个新角色一览 07-05
- 明日方舟终末地开服工业蓝图一览 工业蓝图作用与使用思路解析 07-05
- 原神梦之树怎么开启 梦之树开启条件 07-05
- 帕瓦勇者传说持续伤害阵容搭配推荐 07-05
- 明日方舟:终末地全新玩法 蚀像寻遗怎么玩介绍 07-05