mysql死锁错误怎么处理_死锁日志分析

来源:这里教程网 时间:2026-02-28 20:40:17 作者:

怎么确认发生了MySQL死锁

MySQL发生死锁时,InnoDB会自动检测并终止其中一个事务,返回错误码 1213(Deadlock found when trying to get lock)或 1205(Deadlock found; try restarting transaction)。应用层看到这类报错,基本可判定存在死锁。

但仅靠报错不够——你需要确认是哪两个事务、哪几行数据、什么SQL引发了冲突。关键手段有两个:

开启全局死锁日志:
SET GLOBAL innodb_print_all_deadlocks = ON;
,之后所有死锁都会记录到MySQL错误日志(如
/usr/local/mysql/data/mysqld.local.err
查最近一次死锁快照:
SHOW ENGINE INNODB STATUS\G
,输出中
*** (1) TRANSACTION
*** (2) TRANSACTION
块即为对峙双方

死锁日志里看什么

一份典型死锁日志包含三类核心信息,逐块对照着看:

事务基本信息:事务ID(
TRANSACTION xxx
)、活跃时间(
ACTIVE X sec
)、线程ID(
MySQL thread id
)、执行的SQL(
query id xxx ... updating/inserting...
持有的锁:标记为
HOLDS THE LOCK(S)
,说明该事务已成功加锁的索引页、行位置、锁模式(如
lock_mode X locks rec but not gap
表示对某行加了排他行锁)
等待的锁:标记为
WAITING FOR THIS LOCK TO BE GRANTED
,说明它卡在哪儿——通常正等着对方持有的那把锁释放

重点比对两个事务的

index
名称、
space id
page no
:如果完全一致,说明它们在争同一张表的同一页甚至同一行;若索引不同,可能是联合索引覆盖不全或间隙锁(gap lock)引发的隐式锁定。

快速定位冲突SQL和表结构

从日志里提取出两条关键UPDATE/DELETE语句后,下一步要验证它们是否真的会触发锁冲突:

检查WHERE条件是否命中索引:用
EXPLAIN
看执行计划,没走索引容易升级为表级扫描+大量行锁
确认索引类型:唯一索引上的等值查询(
WHERE id = ?
)只锁匹配行;非唯一索引或范围查询(
WHERE status IN (1,2)
)可能触发next-key lock(行锁+间隙锁),扩大锁定范围
查表当前隔离级别:
SELECT @@tx_isolation;
,可重复读(REPEATABLE-READ)下间隙锁更活跃,比读已提交(READ-COMMITTED)更容易死锁

当场处理与后续规避

线上已报死锁,先稳住服务:

应用层捕获1213/1205错误后,立即重试事务(通常1–2次即可成功) 若频繁死锁影响业务,临时可调大锁等待超时:
SET SESSION innodb_lock_wait_timeout = 60;
(避免长时间挂起,但不解决根本问题)
长期方案聚焦三点:拆小事务、统一加锁顺序(如所有服务按
product_id ASC
更新库存)、给高频WHERE字段补上覆盖索引

死锁不是故障,是并发系统的正常现象。能被自动发现并回滚,恰恰说明InnoDB工作正常。真正要警惕的,是日志里反复出现相同SQL组合的死锁——那往往意味着代码逻辑或索引设计有硬伤。

相关推荐