2023-03-07 16:43

临键锁next-key lock的加锁规则

王姐姐

数据库

(767)

(0)

收藏

背景

MySQL 后面的版本可能会改变加锁策略,所以这个规则只限于截止到现在的最新版本,即 5.x 系列<=5.7.24,8.0 系列 <=8.0.1,实验发现不同版本的差异主要是:索引范围查询的临界值的取舍有所不同。8.0范围查询加锁不包含临界值,7.0范围查询加锁包含临界值。

Next-Key Lock的规则

原则 1:加锁的基本单位是 next-key lock。next-key lock 是前开后闭区间。

原则 2:只有访问到的对象才会加锁。

优化 1:索引上的等值查询,

    命中唯一索引,退化为行锁。

    命中普通索引,左右两边的GAP Lock + Record Lock。

优化 2:

    索引上的等值查询,未命中,所在的Next-Key Lock,退化为GAP Lock 。

索引在范围查询: 

    1.等值和范围分开判断。

    2.索引在范围查询的时候 都会访问到所在区间不满足条件的第一个值为止。

    3.如果使用了倒序排序,按照倒序排序后,检索范围的右边多加一个GAP。哪个方向还有命中的等值判断,再向同方向拓展外开里闭的区间。

构造数据

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

案例1

image.png

分析:

根据原则1,加锁都是next-key lock,所以id=7时所在的Next-Key Lock是(5,10]。

根据优化2,等值查询且未命中表中的一行数据,所以next-key lock退化成GAP lock (5,10)

所以最后锁的区间是(5,10)。

案例2

image.png

分析:

根据优化1,c普通索引,加的是锁(0,5)+5+(5,10)

根据原则 2 ,只有访问到的对象才会加锁,这个查询使用覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁,这就是为什么 session B 的 update 语句可以执行完成。

所以最后的锁范围是(0,10)。

案例3

image.png

分析:

索引范围查询,等值和范围分开判断。所以对10 < c < 11 和 c = 10分别判断。

范围查询 10 < c < 11,在c的范围内在的Next-Key Lock是(10,15]。拿所在区间内不满足条件的第一个值,作为加锁范围的临界值。10和15是区间中第一个不满足条件10 < c < 11的值,所以锁定的范围是(10,15]。

等值查询 c = 10,c是普通索引,所以根据优化2,锁的范围是(5,10)+10+(10,15).。

所以把上面两种情况合起来锁的范围就是(5,15]。

注意:

刚才是mysql7.0版本所以范围查询锁定的区间是(10,15]。如果是8.0范围查询锁定的是(10,15)。区别在于范围查询加锁的时候7.0版本加的是next-key lock。8.0版本范围查询加锁加的是GAP Lock。

案例4

select * from t where id>10 and id<=15 order by id desc for update;

分析:

倒排序后是:20 , 15 , 10 , 5 , 0

按照倒序排序后,查询范围是 10<c<15 , 所以锁的范围是(15,10]。

按照倒序排序后,检索范围的右边多加一个GAP区间。所以加一个(10,5)。

哪边还有命中的等值判断,再向同方向拓展外开里闭的区间。15在左边且有等值命中,所以再向同方向拓展一个外开里闭区间(20,15]。

唯一索引等值查询。id =15命中退化成Record Lock。

所以上面所有的范围是:(20,15] + 15 + (15,10] + (10,5)。

最终加锁范围是:(20,5)

案例5

select * from t where id>=10 and id<15 order by id desc for update;

分析:

倒排序后是:20 , 15 , 10 , 5 , 0

按照倒序排序后,查询范围是 10<c<15 , 所以锁的范围是(15,10]。

按照倒序排序后,检索范围的右边多加一个GAP区间。所以加一个(10,5)。

哪边还有命中的等值判断,再向同方向拓展外开里闭的区间。10在右边且有等值命中,再向同方向拓展外开里闭的区间,因为已经加了一个(10,5),所以在原基础上再向右推展一个外开里闭区间[5,0)。

唯一索引等值查询。id =15命中退化成Record Lock。

所以上面所有的范围是:(15,10] + (10,5) + [5,0)。

最终加锁范围是:(15,0)

————————————————

版权声明:本文为CSDN博主「大阔龙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/wang11yangyang/article/details/118087876

0条评论

点击登录参与评论