记一次mysql死锁问题



 场景:innodb下不同的事务进行更新和插入操作导致数据库死锁,代码如下,在批量插入之前,进行了逻辑删除操作,这段代码在并发情况下出现死锁

堆栈异常: Deadlock found when trying to get lock; try restarting transaction;
更新操作sql
批量插入sql

代码分析

activityId为外键,有外键索引,如果是行级锁肯定不会出现死锁,所以更新的时候肯定不止锁了一条数据

代码中更新操作的是非唯一索引列在innoDB引擎下会触发 next-key lock(间隙锁)。

举例: 表t中有非唯一索引列 test_id为 1, 10, 18, 22, 26的5条数据,此时模拟操作:

事务A 删除一条不存在的数据,数据库就会去找从左开始找最近的索引值

delete from t where test_id= 27;

事务B 删除一条不存在的数据,数据库就会去找从左开始找最近的索引值

delete from t where test_id= 28;

此时事务A和B就会分别产生一个(26,正无穷)间隙锁,然后继续操作

事务A

INSERT INTO t VALUES(27);

此时事务A阻塞,因为事务B在删除操作时拥有了区间锁

事务B

INSERT INTO t VALUES(28);

此时事务B就会死锁,因为事务A在删除操作时拥有了区间锁

解决之道

1、删除时先判断数据是否存在

2、删除和插入分两个事务处理

3、将事务隔离级别设置为读已提交

如果更新数据库存在数据就不会出现死锁,在DELETE FROM ... WHERE ... 和 UPDATE ... WHERE ... 在搜索遇到的每条记录上设置一个独占的间隙锁。 如果通过索引搜索到唯一行就会产生一个索引记录锁。

INSERT 语句对插入的行设置排他(独占)锁。这个锁是一个索引记录锁,而不是间隙锁,并且不会阻止其他会话在插入的行之前区间中插入数据。

死锁,innoDB检测到会剔除一个事务回滚,让另外一个事务完成。

你可能感兴趣的:(记一次mysql死锁问题)