查最近一次死锁详情应使用 show engine innodb status\g,关键区块是 latest detected deadlock,需重点关注“waiting for this lock to be granted”和“holds the lock(s)”两行以定位锁冲突,同时确认 process 权限及 innodb_print_all_deadlocks 配置。

查最近一次死锁详情用 SHOW ENGINE INNODB STATUS\G
这条命令输出里最关键的区块是 LATEST DETECTED DEADLOCK,它会明确列出两个(或多个)事务的 SQL、各自持有的锁、正在等待的锁、事务 ID、隔离级别和 undo log 大小。不要跳过“WAITING FOR THIS LOCK TO BE GRANTED”和“HOLDS THE LOCK(S)”这两行——它们直接告诉你谁在等谁、哪张表哪行被锁住。
常见误操作:只看错误信息里的 Deadlock found when trying to get lock; try restarting transaction 就重试,不查状态。其实死锁不是随机事件,每次发生都对应一个可复现的加锁路径。
- 执行前先确认你有权限:需要
PROCESS权限,否则返回空或报错 - 输出是实时快照,只保留最后一次死锁;若需长期追踪,必须在
my.cnf中设置innodb_print_all_deadlocks = ON - 重点关注
space id和page no,结合information_schema.INNODB_SYS_TABLES可反查出具体表名
确认多表 UPDATE 的实际加锁顺序靠 EXPLAIN FORMAT=TRADITIONAL
UPDATE t1 JOIN t2 ON t1.id = t2.t1_id 的加锁顺序由优化器决定,和你写的表顺序无关。想验证真实行为,不能只看 SQL,得看执行计划。特别是要确认:t1 是否走了主键索引?t2 的 t1_id 字段有没有索引?有没有触发间隙锁?
如果 t2.t1_id 没索引,EXPLAIN 会显示 type: ALL,意味着全表扫描+大量 S 锁,死锁风险陡增。
- 对关联更新语句,先改写为等价
SELECT再EXPLAIN,例如把UPDATE t1 JOIN t2...换成SELECT t1.id FROM t1 JOIN t2 ON t1.id = t2.t1_id WHERE ... - 若
EXPLAIN显示Extra: Using join buffer (hash),说明没走索引,必须补索引 -
ORDER BY t1.id在 UPDATE JOIN 中只是“暗示”,只有当t2.t1_id有索引时才可能生效;否则优化器直接忽略
拆成单表 UPDATE 并控制 ID 升序是更可靠的解法
放弃 UPDATE ... JOIN 不是退让,而是主动消除不确定性。核心逻辑是:应用层先查出要更新的主键列表,确保升序,再分批拼 IN 语句。这样每条 UPDATE 只锁一张表,且所有事务按相同物理顺序加锁。
容易踩的坑是:ID 列表没排序、分批超 max_allowed_packet、SELECT 阶段没加 ORDER BY id 导致后续批次乱序。
- 第一步:
SELECT id FROM t2 WHERE ... ORDER BY id—— 这个ORDER BY必须有,且t2上用于过滤的字段要有索引 - 第二步:拿到 ID 列表后,在应用层严格升序排列(即使数据库已排好,也要再校验),然后按 500 个/批切分
- 第三步:生成类似
UPDATE t1 SET status = 'done' WHERE id IN (101, 102, 105)的语句 —— 注意IN子句内无需ORDER BY,但列表本身必须升序
最容易被忽略的是事务里混了外部依赖
很多死锁看起来是“UPDATE JOIN 引发”,实际根因是事务里夹着 HTTP 调用、Redis 读写或日志落盘。锁持有时间从几毫秒拉长到几百毫秒,哪怕加锁顺序完全一致,也极易触发 Lock wait timeout exceeded 或被其他事务卡住形成循环等待。
真正危险的不是慢 SQL,而是那个在 BEGIN 和 COMMIT 之间默默等了 8 秒的 curl_exec()。
- 所有非 DB 操作必须移出事务块,哪怕只是
file_get_contents()或sleep(1) - 检查 ORM 是否隐式开启了事务(比如 Django 的
@transaction.atomic或 Laravel 的DB::transaction) - 用
SHOW PROCESSLIST查看长时间运行的线程,结合Time列判断是否卡在非 SQL 操作上











