作者:孤独烟
引言
刚起床,本来想去看看电视,结果手抖看到了某个粉丝的留言,于是有了此文。本问题出自某粉丝给我的留言,如下图所示
为啥说是瞎回答呢?
没贴死锁日志
没具体过程
所以,我就靠经验来猜测一下!
正文
先说一个东西
这个语句大家都知道是什么意思了,但是你不要以为只有A表加锁,B表也是加锁的。而且加锁方法还是有讲究的。
老规矩假设B表结构如下,pId为主键,name上无索引
按主键插入
把该粉丝的SQL简化一下,变成
这里虽然是in语句,但是字段为主键。因此,此时索引是会生效的,而且是会逐步锁pId =1,2,7的聚簇索引。也就是说,你可以这么理解,mysql按如下顺序执行的
因此是逐步锁pId =1,2,7的聚簇索引。
说一个特殊情况,如果你执行的是
注意了pId = 8 这一列,在B表是不存在。那么此时存在间隙锁,锁住的是(7,11)这个间隙。
考虑到在这篇文章里要想将insert的加锁机制讲清楚篇幅太小,改天有时间细说。这里大家先这么记
会在索引为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是
也就是说里头的元素是无规律的。为什么呢,如果Session 2执行的SQL是这样递增的,永远无法请求Session 1所获得的锁。所以,我后台询问了一下他
证实了我的猜测!
如何解决
so easy!把隔离级别改成RC就行!RR隔离级别下insert A select B where B.COL=**,innodb层会对B表满足条件的数据进行加锁,但是RC模式下B表记录不会加任何innodb层的锁
总结
嗯,希望我说的该粉丝能懂吧!
●编号464,输入编号直达本文
●输入m获取文章目录
推荐↓↓↓
运维
更多推荐《25个技术类微信公众号》
涵盖:程序人生、算法与数据结构、黑客技术与网络安全、大数据技术、前端开发、Java、Python、Web开发、安卓开发、iOS开发、C/C++、.NET、Linux、数据库、运维等。
领取专属 10元无门槛券
私享最新 技术干货