首先我们这里有一个表t,其中的数据如下图所示
注意哈 update由于操作的最新的值,所以是当前读!
另外一个事务插入 8的时候发生锁
而我对id为10的数据进行更新,却不会被锁住
分析:在执行当前读时,由于id=7不存在,可以理解为在B+树上找7,因此会经过5和10,因此上了nextKey锁(5,10],由于右边界并不等于7,在等值查询上退化成间隙锁(5,10)。
当我把语句改为 id=5,此时给唯一索引进行等值查询,退化为行锁,因此插入8不会被阻塞!
在当前读下,给非唯一索引加锁的时候,会扫描到第一个不等于索引的值,因此加锁为(0,5】,(5,10),注意锁是加在索引上,因此id上没被加锁!!!
进行范围查询,那么加锁范围是多少呢?
插入 8会成功,但是插入10卡住了
说明加锁了id=10这一行
而且id=11能够成功加锁,说明mysql用了比较智能的判断,从而使得语句优化成只锁id=10这一行
改成查10到12之间的
可以看到只锁了id=10的
可以看到只锁了两行!!!
这次session A用字段c来判断,:在第一次用c=10定位记录的时候,索引c上加了(5,10]这个next-key lock后,由于索引c是非唯一索引,没有优化规则,也就是说不会蜕变为行锁,因此最终sesion A加的锁是,索引c上的(5,10] 和(10,15] 这两个next-key lock。
所以从结果上来看,sesson B要插入(8,8,8)的这个insert语句时就被堵住了。
这里需要扫描到c=15才停止扫描,是合理的,因为InnoDB要扫到c=15,才知道不需要继续往后找了。
可以看到15被锁住了,20没有被锁住(MYsql改进的bug 2018之前存在)
加锁是(10,15]
id为10可以正常操作,没有被加锁