MySQL的InnoDB存储引擎在可重复读隔离级别下,通过Next-Key Lock机制实现了对幻读问题的防护,这是很多业务场景下保证数据一致性的重要基础逻辑。

Next-Key Lock的基本定义
Next-Key Lock是InnoDB引擎的一种复合锁,它由两部分组成:
- 记录锁(Record Lock):对索引记录本身的加锁,防止其他事务修改或删除该条记录。
- 间隙锁(Gap Lock):对索引记录之间的间隙加锁,防止其他事务往这个间隙中插入新的记录。
简单来说,Next-Key Lock锁定的是一个左开右闭的区间,比如对于索引值10,对应的Next-Key Lock区间是(5,10],其中5是前一个索引值,10是当前索引值。
Next-Key Lock的加锁规则
Next-Key Lock的加锁逻辑和查询使用的索引类型、查询条件密切相关,核心规则如下:
使用唯一索引的等值查询
如果查询条件是唯一索引的等值查询,且匹配到对应记录,InnoDB会优化为只加记录锁,不会加间隙锁。如果未匹配到记录,会加间隙锁锁定对应的间隙区间。
使用普通索引的等值查询
普通索引的等值查询会加Next-Key Lock,锁定匹配记录所在的区间,同时会向后扫描到第一个不满足条件的记录,对该记录加间隙锁。
范围查询
范围查询会锁定符合条件的所有记录,同时锁定这些记录对应的间隙区间,直到遇到第一个不满足范围条件的记录为止。
Next-Key Lock防幻读的实现逻辑
幻读指的是同一个事务中,两次执行相同的范围查询,第二次查询出现了第一次查询没有的新记录。Next-Key Lock通过锁定间隙,阻止其他事务插入符合查询条件的新记录,从而避免幻读。
我们来看一个具体的示例,首先创建测试表和测试数据:
-- 创建测试表,id为普通索引
CREATE TABLE test_next_key (
id INT,
name VARCHAR(20),
INDEX idx_id (id)
) ENGINE=InnoDB;
-- 插入测试数据
INSERT INTO test_next_key VALUES (1, 'a'), (3, 'b'), (5, 'c'), (7, 'd');
开启两个事务,事务A执行范围查询并加锁:
-- 事务A START TRANSACTION; -- 查询id大于3小于7的记录,加排他锁 SELECT * FROM test_next_key WHERE id > 3 AND id < 7 FOR UPDATE;
此时事务A会对id=5的记录加记录锁,同时对(3,5]和(5,7]两个区间加间隙锁,也就是锁定了(3,7)这个整个区间。
此时事务B尝试插入符合查询条件的新记录:
-- 事务B START TRANSACTION; -- 尝试插入id=6的记录,该记录属于事务A锁定的区间 INSERT INTO test_next_key VALUES (6, 'e'); -- 该语句会被阻塞,直到事务A提交
因为事务B插入的id=6的记录落在事务A锁定的(3,7)区间内,所以插入操作会被阻塞,直到事务A提交释放锁之后才能执行。这样事务A再次执行相同的范围查询时,就不会出现新的记录,从而避免了幻读。
注意事项
- Next-Key Lock只在可重复读和串行化隔离级别下生效,读已提交隔离级别下只会加记录锁,无法防幻读。
- 如果查询没有使用索引,InnoDB会进行全表扫描,此时会对所有记录的间隙加锁,相当于锁表,会影响并发性能。
- 间隙锁之间不会互斥,多个事务可以同时持有相同区间的间隙锁,但是插入操作会因为记录锁的互斥被阻塞。
理解Next-Key Lock的逻辑,能帮助我们在开发过程中合理设计索引和查询语句,避免不必要的锁冲突,同时保证业务数据的一致性。
MySQLNext_Key_Lock防幻读事务隔离级别修改时间:2026-06-19 20:15:26