【Mysql死锁如何排查?insert on duplicate死锁排查过程分析】通过分析死锁日志,我们可以找到发生死锁的SQL,以及相关等待的锁,我们再对对应的SQL进行加锁分析,其实问题就迎刃而解了 。
OK,我们回到对应的SQL,insert into song_rank(songId,weight) values(16,100) on duplicate key update weight=weight+1 执行过程到底加了什么锁呢?
① insert加锁策略
insert语句会对插入的这条记录加排他记录锁,在加记录锁之前还会加一种 GAP 锁,叫做插入意向(insert intention)锁,如果出现唯一键冲突,还会加一个共享记录(S)锁 。
(SQL加锁分析非常重要,在这里给大家推荐一篇文章,讲的非常好,解决死锁之路 - 常见 SQL 语句的加锁分析)
② insert on duplicate key加锁验证
为了验证一下insert on duplicate key加锁情况,我们拿上面demo的事务1和2在走一下流程 。
事务1:
mysql> begin; //第一步Query OK, 0 rows affected (0.00 sec)mysql> insert into song_rank(songId,weight) values(15,100) on duplicate keyupdate weight=weight+1; //第二步Query OK, 1 row affected (0.00 sec)事务2(另开窗口):
mysql> begin; //第三步Query OK, 0 rows affected (0.00 sec)mysql> insert into song_rank(songId,weight) values(16,100) on duplicate key update weight=weight+1; // 第四步使用show engine innodb status查看当前锁请求信息,如图:
文章插图
事务2持有:IX锁(表锁),gap x锁,insert intention lock(在等待事务1的gap锁)
所以,insert on duplicate 执行过程会上这三把锁 。
(5)死锁原因分析
回归到本文开头介绍的死锁案发模拟现场(事务1,2,3)以及死锁日志现场,
案发后事务1的锁:
文章插图
案发后事务2的锁:
文章插图
案发复原路线:
首先,执行事务1执行: begin; insert into song_rank(songId,weight) values(15,100) on duplicate key update weight=weight+1; 会获得 gap锁(10,20),insert intention lock(插入意向锁)
接着,事务2执行: begin; insert into song_rank(songId,weight) values(16,100) on duplicate key update weight=weight+1; 会获得 gap锁(10,20),同时等待事务1的insert intention lock(插入意向锁) 。
再然后,事务3执行: begin; insert into song_rank(songId,weight) values(18,100) on duplicate key update weight=weight+1; 会获得 gap锁(10,20),同时等待事务1的insert intention lock(插入意向锁) 。
最后,事务1回滚(rollback),释放插入意向锁,导致事务2,3同时持有gap锁,等待insert intention锁,死锁形成!
锁模式兼容矩阵(横向是已持有锁,纵向是正在请求的锁):
兼容性 Gap Insert Intention Record Next-Key Gap 兼容 兼容 兼容 兼容 Insert Intention 冲突 兼容 兼容 冲突 Record 兼容 兼容 冲突 冲突 Next-Key 兼容 兼容 冲突 冲突 这是MySql5.7的一个bug
04 如何避免该insert on duplicate死锁问题4.1 把insert on duplicate改为insert
try{ insert(); }catch(DuplicateKeyException e){ update(); }因为insert不会加gap锁,所以可以避免该问题 。
4.2 更改MySql版本
既然这是MySql5.7的一个bug,那么可以考虑更改Mysql版本 。
4.3 尽量减少使用unique index
gap锁跟索引有关,并且unique key 和foreign key会引起额外的index检查,需要更大的开销,所以我们尽量减少使用不必要的索引 。
05 本文总结(重要)本文介绍了MySql5.7死锁的一个bug 。我们应该怎样去排查死锁问题呢?
- show engine innodb status;查看死锁日志
- 找出死锁SQL
- SQL加锁分析
- 分析死锁日志(持有什么锁,等待什么锁)
- 熟悉锁模式兼容矩阵,InnoDB存储引擎中锁的兼容性矩阵
推荐阅读
- Java架构-MYSQL大数据量下的操作与优化
- 做淘宝如何选品!给新手几个建议! 淘宝选品技巧
- 女性冬季如何养生 7个误区需注意
- 如何提高淘宝直播间流量 看淘宝直播费流量吗
- 秋季吃火锅要注意正确方式 如何吃火锅才正确
- 天猫商家如何开通隔日达服务 天猫发货时效规定48小时
- 秋季养生如何养好肺气?多吃白色食物
- 秋季养生防“燥”为主 女人秋季如何养生
- 秋季如何养生 早起五个小常识需谨记
- 轻松鉴别普洱老茶,如何鉴别陈年柑普茶