瞎回答一个粉丝的死锁问题!
Posted 孤独烟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了瞎回答一个粉丝的死锁问题!相关的知识,希望对你有一定的参考价值。
引言
刚起床,本来想去看看电视,结果手抖看到了某个粉丝的留言,于是有了此文。本问题出自某粉丝给我的留言,如下图所示
为啥说是瞎回答呢?没贴死锁日志
没具体过程
所以,我就靠经验来猜测一下!
正文
先说一个东西
insert into A select * from B;
这个语句大家都知道是什么意思了,但是你不要以为只有A表加锁,B表也是加锁的。而且加锁方法还是有讲究的。
老规矩假设B表结构如下,pId为主键,name上无索引
按主键插入
把该粉丝的SQL简化一下,变成
insert A表 select * from B表 where 主键 in (1,2,7)
这里虽然是in语句,但是字段为主键。因此,此时索引是会生效的,而且是会逐步锁pId =1,2,7的聚簇索引。也就是说,你可以这么理解,mysql按如下顺序执行的
insert A表 select * from B表 where 主键 in (1);
insert A表 select * from B表 where 主键 in (2);
insert A表 select * from B表 where 主键 in (7);
因此是逐步锁pId =1,2,7的聚簇索引。
说一个特殊情况,如果你执行的是
insert A表 select * from B表 where 主键 in (8)
注意了pId = 8 这一列,在B表是不存在。那么此时存在间隙锁,锁住的是(7,11)这个间隙。
考虑到在这篇文章里要想将insert的加锁机制讲清楚篇幅太小,改天有时间细说。这里大家先这么记
insert into B values (13,55);
会在索引为pId=13位置加上锁,并在(11,+∞)的位置加上插入意向锁。插入意向锁、间隙锁和行锁的兼容性如下
表注:横向是已经持有的锁,纵向是正在请求的锁。
好了。。现在可以重现死锁的场景了。如下图所示
如图所示
(1) Session 1 在(11,+∞)的位置加上插入意向锁,并获得pId=13记录锁。
(2) Session 2 意图获得(13,+∞)的间隙锁,根据上方的兼容性表。此时存在插入意向锁,因此间隙锁可以获得。
(3) Session 1 意图获得(14,+∞)的插入意向锁,根据上方的兼容性表。此时存在间隙锁,因此无法获得插入意向锁,等待Session2释放锁
(4) Session 2 又想获得得pId=13记录锁,因此等待Session 1 释放锁。
于是,死锁形成!
注意了,因为这里都是我的猜测。我假设执行的SQL是
insert into B1 select * from B where pId in (20,13);
也就是说pId in (20,13)
里头的元素是无规律的。为什么呢,如果Session 2执行的SQL是pId in (20,30,32,35,36...)
这样递增的,永远无法请求Session 1所获得的锁。所以,我后台询问了一下他
证实了我的猜测!
如何解决
so easy!把隔离级别改成RC就行!RR隔离级别下insert A select B where B.COL=**,innodb层会对B表满足条件的数据进行加锁,但是RC模式下B表记录不会加任何innodb层的锁
总结
嗯,希望我说的该粉丝能懂吧!
以上是关于瞎回答一个粉丝的死锁问题!的主要内容,如果未能解决你的问题,请参考以下文章