MySQL5.6.33,隔离级别是RR。表结构及数据:
Create table t1(id int not null primary key auto_increment,c1 int,c2 int,c3 int, unique key(c1),unique key(c2)); insert into t1(c1,c2,c3) values(1,3,4),(6,6,10),(9,9,14);insert into t1 (c1,c2,c3) values(4,4,1);
insert into t1 (c1,c2,c3) values(4,4,2);
insert into t1 (c1,c2,c3) values(4,4,3);
commit;Update t1 set c3=5 where c1=4;
Update t1 set c3=5 where c1=4;
deadlock;从死锁日志上可以看到:
TRANSACTION 7973:
Update t1 set c3=5 where c1=4语句在等待二级索引c1上(4,6)上的X类型的记录锁(lock_mode X locks rec but not gap)
TRANSACTION 7974:
拥有二级索引c1上(4,6)上S类型的next key锁(lock mode S),等待申请(4,6)上的记录锁(lock_mode X locks rec but not gap)
但从死锁日志上只看到两个update语句互相等待,不知道业务逻辑场景的话,很难找到原因。
注:这里留下疑问,为什么主键是6呢,不是4?这个和自增键有关,关于自增值这里不做过多考虑,感兴趣的自行测试分析。
1)关于insert唯一键加锁时重复键判断加S类型next-key锁的加锁原理见之前博客:
https://blog.csdn.net/yanzongshuai/article/details/79326637
以及https://blog.csdn.net/yanzongshuai/article/details/79301868
注意,这里发生重复键加S 类型next key锁时,不论是什么隔离级别,都会加这样的锁。
2)关于隐式锁转换显式锁流程见之前博客:
https://blog.csdn.net/yanzongshuai/article/details/79306514
https://blog.csdn.net/yanzongshuai/article/details/79254031
https://blog.csdn.net/yanzongshuai/article/details/79252679
3)关于update加锁原理见之前博客:
https://blog.csdn.net/yanzongshuai/article/details/80870949
https://blog.csdn.net/yanzongshuai/article/details/80870957
https://blog.csdn.net/yanzongshuai/article/details/80872095
1)session1执行insert into t1 (c1,c2,c3) values(4,4,1);实际上是没有加任何锁的。
2)session2执行insert into t1 (c1,c2,c3) values(4,4,2);二级索引(4)和session1的发生冲突,使session1的隐式锁转换成显式锁;发生唯一冲突,则对(4)加S类型的next key锁,此时session1已经加了X锁,发生等待;
3)session3执行insert into t1 (c1,c2,c3) values(4,4,3);同理,等待session1释放二级索引c1(4)上的X锁,申请S类型的next key锁。
4)session1执行commit后,session2和session3报错:ERROR 1062 (23000): Duplicate entry '4' for key 'c1',同时会申请到S类型的next key锁。
5)session2执行Update t1 set c3=5 where c1=4;从之前博客
https://blog.csdn.net/yanzongshuai/article/details/80872095
可知在search阶段会对二级索引记录(4)申请X类型的记录锁。session3已拥有S类型next key锁,所以发生等待;
6)session3再执行Update t1 set c3=5 where c1=4;同理,会申请X类型的记录锁,等待session2释放其S类型next key锁。此时发生死锁。
杨奇龙老师解释可以使用使用insert on duplicate key语句来代替原来的insert语句。这2个语句的加锁不一样,感兴趣的可以研究下。
https://mp.weixin.qq.com/s/96CDhpgu5uUQ7qKYhKgt3w
