记一次mysql死锁问题



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

12284975-64cdb6cd2d66aaaa.png
堆栈异常: Deadlock found when trying to get lock; try restarting transaction;
12284975-463448730949ed49.png
更新操作sql
12284975-5ca88510e5681bd1.png
批量插入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检测到会剔除一个事务回滚,让另外一个事务完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值