Mysql报Deadlock found when trying to get lock; try restarting transaction问题解决

这篇博客探讨了在MySQL中使用ReplaceINTO语句时遇到的行级锁和死锁问题。由于ReplaceINTO在处理唯一索引时会先查询、再删除和插入,这过程中涉及到的S锁和X锁可能导致死锁,特别是在多线程并发情况下。解决方法包括避免根据非主键更新和删除,以及在出现死锁时通过查询INNODB_TRX表并杀死事务来解除。经验教训是尽量避免仅依赖非主键字段的更新操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用的mysql 的 REPLACE INTO 多线程并发处理同一张表导致表死锁。

Mysql锁类型分析

MySQL有三种锁的级别:页级、表级、行级,这个地方我遇到的问题是来自于行级锁,所以重点说一下。

行级锁在使用的时候并不是直接锁掉这行记录,而是锁索引
如果一条sql用到了主键索引(mysql主键自带索引),mysql会锁住主键索引;
如果一条sql操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引.

死锁原理

mysql的两种锁排它锁(X锁)和共享锁(S锁)(mysql还有其他锁,需要了解可以自己去查,这个地方列举两个):

X锁,是事务T对数据A加上X锁时,只允许事务T读取和修改数据A,别的事务就没办法读取和修改,所以也叫排它锁,是互斥的
S锁,是事务T对数据A加上S锁时,其他事务只能再对数据A加S锁,而不能加X锁,直到T释放A上的S锁,别的事务也用加S锁,所以也叫共享锁,是不互斥的
一般造成死锁的原因是因为两个事物添加锁的时候没能及时的解锁释放资源,等到第二个事务要添加锁的时候发现已经被锁,从而造成环路等待,构成死锁条件。

Replace INTO 这个语法的执行过程和原理

Replace INTO 插入数据前会根据Mysql表中的索引字段,去查询有没有和你插入数据的索引字段有重复,
如果有就先将该数据删除在插入新数据。
再删除和插入的过程中就涉及到了一个行级锁问题,这个过程是有事物存在的,
也就是说要么成功更新数据,要么老数据不变,不能发生老的数据删除但是新的数据未插入这种现象
在删除数据之前首先获得这一行数据的锁,然后在做删除和插入的操作,直到操作结束释放该锁

我的程序是多线程并发 Replace INTO同一张表,表有唯一索引,Replace INTO 查询过程加S锁,删除和插入过程加X锁。

有2个线程,

线程1的X锁正准备加上还是还没加上,实际是存在X锁,但是线程2加了s锁,线程1会等待线程2的s锁 线程2的完整事务加了s锁立即就要加x锁,但是线程1的x锁没有释放。造成了环路等待。

解决方法

进行update、delete的时候尽量避开非主键索引,我这里记录一下被锁后应该怎么去解决的方法,首先先用sql查询一下mysql的事务处理表

select * from information_schema.INNODB_TRX  
正常情况下的状态都是RUNNING,但是在被锁之后就会变成LOCK WAIT ,一旦出现这种情况,就得杀死这个进程,如果进程杀不死就只能重启Mysql服务了
杀死进程

kill 进程ID

经验教训

无论前台后台的程序,都不应该存在仅根据非主键的几个字段一查就要update/delete的场景。即使有,也应该改为先把要更新的记录查出来然后逐条按主键id更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值