MySQL死锁时InnoDB自动回滚代价较小事务并抛出错误码1213,这是正常机制。需通过SHOWENGINEINNODBSTATUS定位冲突SQL及加锁顺序,开启innodb_print_all_deadlocks记录全部死锁。常见根因是SQL执行顺序不一致或索引缺失导致大量行锁冲突。
MySQL发生死锁时,很多人的第一反应是赶紧改代码去。实际上,InnoDB自身能够处理这种情况——它会自动回滚代价较小的事务并抛出错误码1213。这不是故障,而是正常机制在运作,它主动打破了僵局。真正需要做的,是定位哪两条SQL在抢同一组资源,以及加锁顺序为何冲突。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
MySQL 检测到死锁后,会直接回滚代价较小的事务,并抛出 Deadlock found when trying to get lock 错误(错误码 1213)。这其实不是真正的问题,而是 InnoDB 的一种自我保护——它主动打破了僵局。真正需要做的,是定位哪两条 SQL 在抢同一组资源,以及它们加锁顺序冲突的根因是什么。
SHOW ENGINE INNODB STATUSG 提取现场信息这个命令是排查死锁最直接、不可或缺的一步。执行后,输出中只看 LATEST DETECTED DEADLOCK 段落,重点关注三块内容,一块都不能少:
query id 后紧跟着的实际 SQL,比如 UPDATE t SET c = c + 1 WHERE id = 2HOLDS THE LOCK(S) 和事务 (2) 的 WAITING FOR THIS LOCK TO BE GRANTED——这直接告诉你谁先占了什么、谁在等什么RECORD LOCKS lock_mode X locks rec but not gap 表示主键上的排他记录锁;若出现 gap 或 next-key,说明涉及间隙锁,大概率与范围查询或非唯一索引相关innodb_print_all_deadlocks 是否开启默认情况下,SHOW ENGINE INNODB STATUS 只保留最近一次死锁信息。如果线上频繁报错但日志里找不到上下文,很可能就是没开全量记录。
SET GLOBAL innodb_print_all_deadlocks = ON;[mysqld] 下加 innodb_print_all_deadlocks = 1,并确保 log_error 路径可写很多团队总把死锁归为“偶发”,其实只要两个事务更新同一组行但顺序不同,就一定会在足够高的并发下复现。
UPDATE orders SET status=2 WHERE id=100; → UPDATE users SET last_order_id=100 WHERE id=5;UPDATE users SET last_order_id=101 WHERE id=5; → UPDATE orders SET status=2 WHERE id=101;orders,再 usersWHERE user_id = 若 user_id 无索引,InnoDB 会全表扫描并锁大量行,极易与其他事务交叉冲突真正难处理的不是单次死锁,而是那些因间隙锁、长事务或 ORM 自动生成 SQL 顺序混乱导致的隐蔽冲突——它们不会立刻报错,但会在高并发时突然爆发。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述