一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识( 三 )

4.2 锁冲突矩阵
简单版矩阵

一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
当我们将gap lock(间隙锁), next key lock(next-key锁), Insert Intention lock(插入意向锁)也加入矩阵时 , 就会复杂很多了
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
说明:
  • not gap: 行锁
  • gap: gap lock
  • next-key: gap + 行锁
小结:
针对上面的矩阵 , 理解下面几个原则即可推导上面矩阵
  • gap lock只会与插入意向锁冲突
  • X行锁会与行锁冲突
  • next key lock: 行锁 + gap锁 锁区间内 , 插入冲突; 行锁的X锁冲突
二、并发插入死锁分析上面属于基本知识点 , 接下来我们看一个实际导致死锁的case
  • 并发插入相同记录导致死锁
0. 表准备
创建一个最简单最基础的表 , 用于演示
CREATE TABLE `t` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;INSERT INTO `t` (`id`) VALUES (1);1. 事务回滚的死锁问题
场景复现:
step1:
-- session1: begin; insert into t values (2);-- session2:begin; insert into t values (2);-- 阻塞-- session3:begin; insert into t values (2);-- 阻塞step2:
-- session1:rollback;
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
原因分析:
死锁日志查看
SHOW ENGINE INNODB STATUS;
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
step1:
  • session1: 插入(id=2) , 会添加一个X + Next Lock锁
  • session2/3: 插入(id=2) , 插入意向锁被阻塞 , 改为持有S + Next Lock锁
step2:
  • session1: 回滚 , 释放X锁
  • session2/3: 竞争X锁 , 只有对方释放S锁 , 才能竞争成功;相互等待 , 导致死锁
2. delete导致死锁问题
和前面操作基本一致 , 只是第一个会话是删除记录
step1:
-- session1: begin; delete from t where id=1;-- session2:begin; insert into t values (1);-- 阻塞-- session3:begin; insert into t values (1);-- 阻塞step2:
-- session1:commit;
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
原因分析和前面基本一致
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
3. insert加锁逻辑
insert中对唯一索引的加锁逻辑
  1. 先做UK冲突检测 , 如果存在目标行 , 先对目标行加S Next Key Lock(该记录在等待期间被其他事务删除 , 此锁被同时删除)
  2. 如果1成功 , 对对应行加X + 插入意向锁
  3. 如果2成功 , 插入记录 , 并对记录加X + 行锁(有可能是隐式锁)
根据上面这个的逻辑 , 那么就会有一个有意思的死锁场景
step1:
-- session1begin; delete from t where id = 1;-- session2begin; delete from t where id = 1;step2:
-- session1insert into t values(1)
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
对应的死锁日志
一次并发插入死锁带来的“教训”,我才清楚这些MySQL锁知识

文章插图
 
关于这个场景详情博文可以参考:记录一次Mysql死锁排查过程
4. 怎么避免死锁呢?
  • 将大事务拆成小事务
  • 添加合理的索引 , 走索引避免为每一行加锁 , 降低死锁的概率
  • 避免业务上的循环等待(如加分布式锁之类的)
  • 降低事务隔离级别(如RR -> RC 当然不建议这么干)
  • 并发插入时使用replace/on duplicate也可以避免死锁
三、总结尽信书则不如 , 以上内容 , 纯属一家之言 , 因个人能力有限 , 难免有疏漏和错误之处 , 如发现bug或者有更好的建议 , 欢迎批评指正 , 不吝感激 。
作者:一灰灰
链接:https://juejin.cn/post/6927197371227095047
来源:掘金




推荐阅读