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

12次阅读

mysql死锁可通过错误码1213/1205识别,再结合SHOW ENGINE INNODB STATUSG查看两个冲突事务的SQL、索引、锁类型及等待关系,并通过EXPLaiN和隔离级别分析根因,最后以重试、拆事务、统一加锁顺序和优化索引规避。

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

怎么确认发生了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 STATUSG,输出中 *** (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 idpage 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组合的死锁——那往往意味着代码逻辑或索引设计有硬伤。

text=ZqhQzanResources