MySQL技术內幕

Next-key Lock

2021-03-22  本文已影响0人  DH大黄

极客时间

间隙锁锁的内容:锁定两个值之间的空隙

间隙锁产生的原因:为了解决幻读问题

锁是加在对应的索引上的,访问到对应的索引,才会向对应的索引上加锁

前提:可重复度级别

描述一下幻读:
产生的前提条件:在可重复度隔离级别下,使用“当前读”出现的一种现象
现象:能够看到其他事务插入的最新数据
描述一下当前读和快照读:
当前读:读取最新版本的数据,并对读取的记录加锁(间隙锁+行锁)(例如 select ... for update)
快照读:看不到其他事务插入的新数据(在执行select操作时生成一张快照,不是开启事务的时候,生成快照之后的变动都无感知)

当前读的方法是:for update,in share mode,update,delete,insert 操作

间隙锁+行锁(next-key lock)(前开后闭区间)

加锁的规则

原则 1:加锁的基本单位是 next-key lock。希望你还记得,next-key lock 是前开后闭区间。

原则 2:查找过程中访问到的对象才会加锁。

优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。(需要命中对应的行)

优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁

一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

对未命中索引的查询,例如d没有索引

image.png

select * from t2 where d = 100 for update。此时间隙锁会锁住全表

limit语句会缩小加锁范围,在找到limit指定的条数之后,不会再继续遍历

next-key lock:加锁的过程
首先是先加间隙锁,然后才加行锁

对非索引字段的加间隙锁,会导致锁表

order by *** desc 会倒序遍历

sql语句分析

表结构

CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

BEGIN;
INSERT INTO `t2` VALUES (0, 0, 0);
INSERT INTO `t2` VALUES (5, 5, 5);
INSERT INTO `t2` VALUES (10, 10, 10);
INSERT INTO `t2` VALUES (15, 15, 15);
INSERT INTO `t2` VALUES (20, 20, 20);
INSERT INTO `t2` VALUES (25, 25, 25);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
select * from t2 where c >= 15 and c <= 20 order by c desc lock in share mode;
对sql进行next-key lock分析
order by c desc 说明需要倒序查找
首先命中20,增加next-key lock (15,20]
c=20由于优化2,向右遍历至第一个不符合不满足为止并退化为间隙锁 (20,25)
c>15,继续向前查找找到不满足为止,访问到c=10
由于原则2,因为10被访问到,所以也需要加上next-key lock,(5,10]
最终推出上锁范围 (5,25)
select * from t2 where c >= 15 and c <= 20 lock in share mode;
对sql进行next-key lock分析
首先命中15,增加next-key lock (10,15]
然后继续遍历,(15,20]
由于等值查询 c = 20,优化2,向右遍历至第一个不符合不满足为止并退化为间隙锁 (20,25)
最终推出上锁范围 (10,25)
上一篇 下一篇

猜你喜欢

热点阅读