MySQL 中如果发生死锁应该如何解决?

发布时间:2026/8/25 5:57:34
MySQL 中如果发生死锁应该如何解决? MySQL 中如果发生死锁应该如何解决死锁两个或多个事务互相持有对方需要的锁双方都在等待对方释放锁互相僵持谁都无法继续执行。InnoDB会自动检测死锁主动回滚代价更小的那个事务另一个事务继续执行。一、怎么发现死锁程序抛出异常Deadlock found when trying to get lock; try restarting transactionMySQL查看死锁日志showengineinnodbstatus;输出结果里LATEST DETECTED DEADLOCK就是最近一次死锁记录可以看到哪两条SQL、锁、事务造成死锁。二、死锁产生的4个必要条件互斥锁是排他的持有并等待事务拿到部分锁等待其他锁不可剥夺锁不能被强制抢走只能自己释放循环等待形成环路等待A等B、B等A破坏任意一个条件就可以消除死锁。三、线上解决、优化方案面试重点1. 业务捕获异常重试InnoDB回滚其中一个事务应用捕获死锁异常做有限次数重试不要无限重试。这是兜底方案不能只靠重试要从根源避免。2. 统一更新资源顺序最有效死锁大多来自更新顺序不一致。事务A更新id1再更新id2事务B更新id2再更新id1会形成循环等待产生死锁。✅优化所有业务永远按主键id从小到大顺序更新记录破坏循环等待条件。3. 尽量缩小事务粒度事务不要写太大事务内部不要做耗时操作网络调用、sleep。事务越快执行完成锁持有时间越短发生锁竞争、死锁概率大幅降低。不要把查询、外部接口调用放到事务里面。4. 减少范围操作避免间隙锁冲突RR隔离级别RR隔离级别临键锁/间隙锁很容易诱发死锁。尽量走索引避免全表扫描防止锁范围扩大互联网很多业务改成RC隔离级别RC没有间隙锁死锁概率显著下降修改RC前提binlog格式设置为ROW。5. 避免一次性操作过多行大批量update/delete拆成分批小SQL减少持有大量行锁。6. 谨慎使用 select … for update尽量精准查询命中唯一索引锁住少量行不要范围查询for update锁范围会很大。四、紧急处理已经发生死锁怎么应急通过show engine innodb status拿到死锁日志定位业务SQLshow processlist找到长时间阻塞事务可以kill掉阻塞会话优化SQL、调整业务更新顺序。补充死锁 vs 锁等待超时死锁互相等InnoDB自动检测回滚一个事务报错死锁。锁等待超时一个事务单纯等锁对方不释放超过innodb_lock_wait_timeout时间直接报错不会自动回滚对方事务。总结发生死锁InnoDB会自动回滚代价小的事务应用层捕获异常有限重试根治手段统一更新记录顺序、缩小事务、避免长事务RR隔离级别间隙锁容易诱发死锁可评估业务是否切换RC通过show engine innodb status分析死锁日志定位问题SQL。