相信大家研究过锁的同学,都知道在唯一索引的范围查询,会锁下一个记录,在mysql45讲中,作者也提到过,并且认为是个bug,但是官方没有确认,针对这个问题,我也思考了下,下面描述下我的理解,如果不正确,麻烦指正。
mysql> show create table dba_test2\G *************************** 1. row *************************** Table: dba_test2 Create Table: CREATE TABLE `dba_test2` ( `id` int NOT NULL, `age` int DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `udx_age` (`age`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 select * from dba_test2; +-----+------+ | id | age | +-----+------+ | 1 | 11 | | 2 | 15 | | 3 | 20 | session1; ysql> select * from dba_test2 where age <=15 for update; +------+------+ | id | age | +------+------+ | 1 | 11 | | 2 | 15 | +------+------+ 2 rows in set (0.01 sec) session2 --被阻塞 delete from dba_test2 where age=20;
我的理解,如果有这样的事务begin;update dba_test2 set age=88 where age=15;select * from dba_test2 where age <=15 for update; 这样select的时候,看到id=15的记录已经没有了,会向后查找定位记录,找到后加锁,那为什么不向前查找定位记录,向前的话加的锁范围就不对了,导致幻读。所以是向后定位一个记录,如果没有20这个记录,那么就会在最大值上加范围锁。 针对这个case,8.0优化了,只是锁了15之前的记录,应该是去查15这条记录是否真实存在了,存在就加15之前的,不存在就向后多加一个范围。8.0针对最大值的范围,查询没有缩小范围,select * from dba_test2 where id <=3.,将最大值这个范围锁上了,这个比较奇怪,按理说都是下一个记录锁,处理的方式应该跟上面的方式一样,看来还是没有彻底解决这个问题。 有兴趣学习源码的加群一起学习啊 QQ: 700072075
