//
insert on duplicate key死锁问题分析
//
开始今天的文章之前,先说明下昨天文章中的一个错误,昨天文章最后说replace into带来的死锁问题可以使用insert into duplicate key update的方法来解决,今天实际测试的时候,还是遇到了一些问题,改方法并没有完全解决死锁的问题,来看测试的结果。
首先,我们新建一个test表,其中包含3列,a,b,c,其中a是主键,b是唯一索引,c是普通列,往test表中插入一条记录,该记录如下:(2020,5,5),然后在3个会话中执行下面的语句:
死锁信息对应的命令行输出如下:
mysql:yeyztest 22:14:18>>begin;
Query OK, 0 rows affected (0.00 sec)
mysql:yeyztest 22:14:20>>replace into test_replace values (2024,5,5);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
mysql:yeyztest 22:14:31>>replace into test_replace values (2024,5,5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
这是在使用replace的方法进行插入的时候遇到的问题。当我们将3个session中的replace的方法全部换成insert into ... on duplicate key的时候,该问题没有得到解决,还是报一样的错误,如下:
mysql :yeyztest 22:15:44>>begin;
Query OK, 0 rows affected (0.00 sec)
mysql :yeyztest 22:20:16>>insert into test_replace values (2025,5,5) on duplicate key update id=2024;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
查询了MySQL在insert的时候的加锁情况,官网上的介绍如下:
https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html
详读官方文档上的这个文章,相信可以解决你的疑问。
该网址上面的例子,几乎完整的复现了上述死锁的情况,就是说,加入有两条并发的insert操作要对同一条记录加共享锁,而此时这条记录又被其他事务加上了排它锁,当排它锁的事务回滚或者提交之后,两个并发的insert操作是会发生死锁的,原因是由于这两条并发的insert操作,都对这条记录加上了共享锁,所以都无法获取该条记录的排它锁,除非一条insert语句回滚。
最后给出一张锁的兼容性的表供大家参考:
有帮助的话还希望点下再看哈