当前位置:网站首页>MySQL locking case analysis
MySQL locking case analysis
2022-08-01 16:32:00 【CaptHua】
1.锁的种类
InnoDB有三种行锁的算法
Record Lock
总是会去锁住索引记录, 如果表没有设置索引, The engine uses an implicit primary key for locking
Gap Lock 锁定一个范围, 不包含自身
Next-Key Lock: Gap Lock+Record Lock 范围+自身, 解决幻读问题,前开后闭
previous-key locking:前闭后开
2.加锁规则
前提:RR隔离级别,版本:版本:5.x 系列 <=5.7.24,8.x系统<=8.0.13
原则1:加锁的基本单位是 next-key lock.next-key lock 是前开后闭区间.
原则2:查找过程中访问到的对象才会加锁.
优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁.
优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁.
一个bug:A range query on a unique index accesses the first value that does not satisfy the condition(包含)为止.(8.0.25已经修复)
注意:
- 非唯一索引,Need to traverse right to the first unqualified value to stop
- 范围查找就往后继续找
- 执行 for update 时,系统会认为你接下来要更新数据,因此会顺便给主键索引上满足条件的行加上行锁
- Conflicting locks can be held on a gap by different transactions(conflicting locks can be held on a gap by different transactions)
- Read-commit isolation level optimization:There is an optimization under read-commit isolation level,即:语句执行过程中加上的行锁,在语句执行完成后,就要把“不满足条件的行”上的行锁直接释放了,不需要等到事务提交.也就是说,读提交隔离级别下,锁的范围更小,锁的时间更短,这也是不少业务都默认使用读提交隔离级别的原因.
3.案例
示例数据
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);
案例一:等值查询间隙锁
t1 | t2 | t3 |
update t set d=d+1 where id=7; | ||
insert into t values (8,8,8); 阻塞 | ||
update t set d=d+1 where id=10; 成功 |

分析
t中没有id=7的记录,According to the locking rules:
1. 根据 原则1,加锁单位是 next-key lock,session A 加锁范围就是 (5,10]
2. 同时根据优化 2,这是一个等值查询 (id=7),而 id=10 不满足查询条件,next-key lock 退化成间隙锁,因此最终加锁的范围是 (5,10)
所以事务2要往这个间隙里面插入 id=8 的记录会被锁住,但是事务3修改 id=10 这行是可以的
案例二:非唯一索引等值锁
t1 | t2 | t3 |
select id from t where c = 5 lock in share mode | ||
update t set d=d+1 where id=5 | ||
insert into t values (7,7,7) 阻塞 |

分析
t1给索引 c 上 c=5 的这一行加上读锁
1.根据原则 1,加锁单位是 next-key lock,因此会给 (0,5] 加上 next-key lock
2.因为c不是唯一索引,So you need to traverse down to the first unqualified value to stop.因此访问 c=5 This record cannot be stopped immediately,需要向右遍历,查到 c=10 才放弃.根据原则 2,访问到的都要加锁,因此要给 (5,10]加 next-key lock
3.根据优化 2:等值判断,向右遍历,最后一个值不满足 c=5 这个等值条件,因此退化成间隙锁 (5,10).
4.根据原则 2 ,只有访问到的对象才会加锁,这个查询使用覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁,因此 t2的 update 语句可以执行完成
访问到的对象才会加锁,这个“对象”指的是列,不是 记录行. 加锁,是加在索引上的. 列上,有索引,就加在索引上; 列上,没有索引,Just added to the primary key index
t3要插入一个 (7,7,7) 的记录,就会被 t1 的间隙锁 (5,10) 锁住
案例三:主键索引范围锁
t1 | t2 | t3 |
select * from t where id>=10 and id | ||
insert into t values (8,8,8); OK insert into t values (13,13,13) 阻塞 | ||
update t set d=d+1 where id=15 阻塞 |

分析
1.开始执行的时候,要找到第一个 id=10 的行,因此本该是 next-key lock(5,10]. 根据优化 1, 主键 id(唯一索引) 上的等值条件,退化成行锁,只加了 id=10 这一行的行锁
2.范围查找就往后继续找,找到 id=15 这一行停下来,因此需要加 next-key lock(10,15]
所以,t1 The scope of the lock is on the primary key index,行锁 id=10 和 next-key lock(10,15]
案例四:非唯一索引范围锁
t1 | t2 | t3 |
select * from t where c>=10 and c | ||
insert into t values (8,8,8) 阻塞 | ||
update t set d=d+1 where c=15 阻塞 |
分析
在第一次用 c=10 定位记录的时候,索引 c 上加了 (5,10] 这个 next-key lock 后,由于索引 c 是非唯一索引,没有优化规则,也就是说不会蜕变为行锁,因此最终 t1 加的锁是 索引 c 上的 (5,10] 和 (10,15] 这两个 next-key lock
案例五:唯一索引范围锁 bug
t1 | t2 | t3 |
select * from t where id>10 and id | ||
update t set d=d+1 where id=20 阻塞 | ||
insert into t values (16,16,16) 阻塞 |
t1 是一个范围查询,按照原则 1 的话,应该是索引 id 上只加 (10,15]这个 next-key lock,并且因为 id 是唯一键,所以循环判断到 id=15 这一行就应该停止了,但是实现上,InnoDB It will scan backward until the first behavior that does not meet the conditions,也就是 id=20.而且由于这是个范围扫描,因此索引 id 上的 (15,20]这个 next-key lock 也会被锁上
这里锁住 id=20 这一行的行为,其实是没有必要的.因为扫描到 id=15,就可以确定不用往后再找了.但实现上还是这么做了,So this can be considered a bug
案例六:非唯一索引上存在"等值"的例子
Insert one more record into the table
insert into t values (30,10,30);
此时索引c如下图所示

t1 | t2 | t3 |
delete from t where c=10 | ||
insert into t values (12,12,12) 阻塞 | ||
update t set d=d+1 where c=15 |

分析
1. t1在遍历的时候,先访问第一个 c=10 的记录.同样地,根据原则 1,这里加的是 (c=5,id=5) 到 (c=10,id=10) 这个 next-key lock
2. t1向右查找,直到碰到 (c=15,id=15) 这一行,循环才结束.根据优化 2,这是一个等值查询,向右查找到了不满足条件的行,所以会退化成 (c=10,id=10) 到 (c=15,id=15) 的间隙锁
因此,delete 语句在索引 c 上的加锁范围,就是下图中蓝色区域覆盖的部分

案例七:limit 语句加锁
t1 | t2 |
delete from t where c=10 limit 2 | |
insert into t values (12,12,13) OK |
分析
t1 的 delete 语句加了 limit 2.表 t 里 c=10 的记录有两条,因此加不加 limit 2,删除的效果都是一样的,但是加锁的效果却不同.可以看到,t2 的 insert 语句执行通过了,跟案例六的结果不同
delete 语句明确加了 limit 2 的限制,因此在遍历到 (c=10, id=30) 这一行之后,满足条件的语句已经有两条,循环就结束了
因此,索引 c 上的加锁范围就变成了从(c=5,id=5) 到(c=10,id=30) 这个前开后闭区间,(c=10,id=30)之后的这个间隙并没有在加锁范围里,因此 insert 语句插入 c=12 是可以执行成功的.如下图所示:

案例八:死锁
t1 | t2 |
select id from t where c=10 lock in share mode; | |
update t set d=d+1 where c=10 阻塞 | |
insert into t values (8,8,8); | |
[40001][1213] Deadlock found when trying to get lock; try restarting transaction |
分析
1. t1 启动事务后执行查询语句加 lock in share mode,在索引 c 上加了 next-key lock(5,10] 和间隙锁 (10,15);
2. t2 的 update 语句也要在索引 c 上加 next-key lock(5,10] ,进入锁等待.
先加(5, 10)的间隙锁,然后加10的行锁,锁住,Haven't had time to add yet(10,15]的next-key lock呢,就被10The row lock is locked,所以这个时候t1如果插入(12,12,12)是不会被session BThe gap lock is locked.
3. 然后 t1 要再插入 (8,8,8) 这一行,被 session B 的间隙锁锁住.由于出现了死锁,InnoDB 让 session B 回滚
t2 中 “加 next-key lock(5,10] ” 操作,实际上分成了两步,先是加 (5,10) 的间隙锁,加锁成功;然后加 c=10 的行锁,这时候才被锁住的.
总结
It can be used when analyzing locking rules next-key lock 来分析.具体执行的时候,是要分成间隙锁和行锁两段来执行的
在删除数据的时候尽量加 limit.这样不仅可以控制删除数据的条数,让操作更安全,还可以减小加锁的范围
边栏推荐
- Vulnhub靶机:HARRYPOTTER_ NAGINI
- MUI as a mobile phone to return to the action bar
- 显示为弹出窗口是什么意思(电脑总是弹出广告)
- 使用Canvas 实现手机端签名
- 软件测试谈薪技巧:同为测试人员,为什么有人5K,有人 20K?
- OpenCV-resize函数「建议收藏」
- 行程排序(暑假每日一题 12)
- The untiy Resources directory dynamically loads resources
- 70后夫妻给苹果华为做“雨衣”,三年进账7.91亿
- PHP 安全漏洞:会话劫持、跨站点脚本、SQL 注入以及如何修复它们
猜你喜欢

js邯郸市地图网页源码下载

便携烙铁开源系统IronOS,支持多款便携DC, QC, PD供电烙铁,支持所有智能烙铁标准功能

网站备案后没有找到站点 您没有将此域名或IP绑定到对应站点! 配置文件未生效!

MySQL data processing of authorization 】 【

MLX90640 红外热成像仪测温模块开发笔记(完整版)

ESP8266-Arduino编程实例-74HC595位移寄存驱动

Ant discloses the open source layout of core basic software technology for the first time

IronOS, an open source system for portable soldering irons, supports a variety of portable DC, QC, PD powered soldering irons, and supports all standard functions of smart soldering irons

工业制造行业的低代码开发平台思维架构图

05 doris 集群搭建
随机推荐
百图生科卓越开发者计划全面升级暨《计算免疫问题白皮书》发布
主流定时任务解决方案全横评
uwsgi配置文件启动
Synchronized原理
MySQL [create and manage tables]
How to Efficiently Develop Jmix Extension Components
canvas粒子雨动画js特效
pytorch测试的时候为何要加上model.eval()?
pytorch中tensor转成图片保存
BPM是什么意思?BPM的优势及好处有哪些?
Ant discloses the open source layout of core basic software technology for the first time
MLX90640 红外热成像仪测温模块开发笔记(完整版)
Go unit tests
【paper】Cam2BEV论文浅析
lombok builder重写
如何有效地开发 Jmix 扩展组件
C#的FTP帮助类
bug- 切换代理服务器与同步 bug
1个月写900多条用例,2线城市年薪33W+的测试经理能有多卷?
软件测试谈薪技巧:同为测试人员,为什么有人5K,有人 20K?