MySQL可重复读隔离级别下,普通索引范围查询,小于查询或者小于等于查询,查询到第一个不符合条件的索引时,为什么临键锁不会退化为间隙锁?如果是为了防止幻影数据,可以给出一个例子吗?目前我认为将第一个不满足查询条件的索引可以将临键锁退化为间隙锁,仍然可以防止幻影数据。请各位大佬答疑,感谢!
数据准备
表结构如下:
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `student__index_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
表中数据SQL及图片
INSERT INTO student (id, name, age) VALUES (1, '路飞', 19);
INSERT INTO student (id, name, age) VALUES (5, '索隆', 21);
INSERT INTO student (id, name, age) VALUES (10, '山治', 22);
INSERT INTO student (id, name, age) VALUES (15, '乌索普', 20);
INSERT INTO student (id, name, age) VALUES (20, '香克斯', 39);
执行SQL
普通索引范围查询,第一个不符合条件索引,仍然被加临键锁,没有退化为间隙锁
begin;
select * from student where age < 25 for update;
select * from performance_schema.data_locks;
commit;
加锁数据:
二级索引age加锁区间:(-无穷,19],(19,20],(20,21],(21,22],(22,39]
尝试:普通索引范围查询小于,小于等于条件都尝试过,没有出现第一个不符合条件的索引的临键锁退化为间隙锁的现象。
希望获得结果:为什么不发生退化的原因?
在MySQL的可重复读(RR)隔离级别下,普通索引范围查询中不发生临键锁退化为间隙锁的根本原因是为了完全防止幻读现象。
假设事务A执行:
如果临键锁在遇到第一个不满足条件的记录(age=39)时退化为间隙锁,那么只会锁住(22,39)这个间隙,而不会锁住age=39这个记录本身。
现在考虑如果事务B执行:
如果事务A只有间隙锁而没有临键锁,那么事务B可以成功修改age=39的记录,使其变为age=24。这就导致了幻读问题,因为如果事务A再次执行最初的查询,会发现多了一条记录(原来的age=39现在变成了age=24)。