暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL锁之GAP Lock

南北技术笔记 2020-11-23
2047
被前端气死的一天



    InnoDB常见的加锁操作有三种,Record Lock、GAP Lock和Next-key Lock,Next-key Lock是Record Lock、GAP Lock的组合,所以也可以将Next-key Lock理解为一个概念,只是两种锁算法的组合。
    Record Lock:锁定索引对应的记录。
    GAP Lock:要么锁定索引记录中间的值,要么锁住第一个索引记录前的值或者最后一个索引记录后的值。
我们今天重点说GAP Lock。

 

GAP Lock只会出现在RR隔离级别下!

GAP Lock只会出现在RR隔离级别下!

GAP Lock只会出现在RR隔离级别下!



普通索引下的GAP Lock


mysql> show create table user;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user | CREATE TABLE `user` (
`id` int NOT NULL,
  `score` int DEFAULT NULL,
KEY `socre` (`score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
当前表结构,只有一个普通索引score。我们下面的测试都是在普通索引score的基础上完成的。

从上图可以发现,插入score为10、15、25都插入失败,score为30的时候插入成功。原因是SessionA的select操作,不止锁了score为20的行。

从数据库的记录和索引字段,我们可以分析,这个表的间隙被分成了下面的情况:

  • (negative infinity,10)

  • (10,20),

  • (20,30),

  • (30,40)

  • (40,positive infinity)

而RR隔离级别,默认是使用Next-key Lock,Next-Key Lock加锁有下面几个规则。

  1. Next-Key Lock是前开后闭区间

  2. 查找过程中访问到的对象才会加锁

  3. 索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为record lock。

  4. 索引上的等值查询,向右遍历时且最后一个值不满足等值条件时,next-key lock退化为gap lock。

分析上图的两个事务的操作,在A事务加锁之后,实际的加锁范围是[10,30),sql查询流程如下:

  1. 通过score索引,找到第一个值,score=10,不满足条件,继续向下寻找。

  2. 找下一个节点score=20,符合条件,会加上行锁和间隙锁。此时的加锁状态是(10,20];但是根据规则2,查找过程访问到的上一个记录score=10,所以会将10也锁住,加锁范围变成[10,20]。

  3. score不是唯一索引,所以会继续向下寻找,下一个节点为30,满足规则2,所以会加上(20,30],但是30不满足等值查询score=20,所以根据第4条规则next-key lock退化为gap lock(20,30)。

  4. 至此,事务加锁结束,最终的加锁范围是[10,30)



唯一索引下的GAP Lock

mysql> show create table user;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user | CREATE TABLE `user` (
`id` int NOT NULL,
`score` int DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `socre` (`score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

唯一索引情况,查询的结果包含想要查询的记录,不会产生间隙锁。

唯一索引情况,查询结果不包含想要的记录,会产生间隙锁。

唯一索引下,如果查询结果不包含想要的记录,会产生间隙锁。从上图和Next-key Lock加锁规则我们可以得出,上图Session A操作之后,产生的锁范围是[6,10),不过因为是唯一索引,所以查询id为6或id为10的时候报错不是提示等待超时,而是直接提示重复。



Gap Lock加锁总结

  • 间隙锁锁定的是索引记录之前和之后的一个间隙范围。

  • 可以对同一个间隙重复加间隙锁。

  • 间隙锁可能造成死锁。

  • 间隙锁是RR隔离级别下的。

  • 间隙锁只影响一般索引,对于唯一索引或者主键,如果查询的结果包含这个记录,那么另外的会话插入该记录前后,不会产生间隙锁;如果查询结果不包含这个记录,另外的会话插入该记录前后的间隙,会产生间隙锁。

   



END




参考:

http://guitoo.cc/wordpress/2019/05/07/

https://segmentfault.com/a/1190000013307132


文章转载自南北技术笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论