MySQL的死锁是指多个事务相互持有对方所需锁且不释放,导致无限等待的现象。系统内置死锁检测会自动回滚其中一个事务并抛出异常,使另一事务继续执行。要快速应对已发生的死锁并从根源上避免,需掌握以下紧急处理和永久方案。

你现在的核心需求分两步:
MySQL 内置死锁检测(默认开启),一旦检测到死锁:
Deadlock found when trying to get lock; try restarting transaction 异常结论:已发生的死锁不需要人工干预,MySQL 自己会秒级解决。
死锁已经发生,必须查日志定位原因,执行命令:
-- 查看最近一次死锁的详细信息SHOW ENGINE INNODB STATUS;
在结果中找到 LATEST DETECTED DEADLOCK 段落,里面会告诉你:
这是解决死锁的唯一依据。
极少数情况(关闭了死锁检测),事务会一直卡住,执行以下命令手动处理:
-- 1. 查看正在运行的事务,找到卡住的 IDSELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;-- 2. 杀掉卡住的事务KILL 事务ID;
死锁无法100%杜绝,但99%的死锁都能通过规范避免。
坏例子
BEGIN;UPDATE 表 SET ...;-- 这里调用了外部接口,耗时3秒,锁一直持有,极易死锁COMMIT;
死锁的本质:访问顺序相反
解决方案:
所有业务代码,必须按相同顺序操作表/行
例如:统一先操作库存,再操作订单。
无索引会导致行锁升级为表锁,死锁概率暴增。
-- 错误:无索引,会锁全表UPDATE user SET money=100 WHERE name='张三'; -- 正确:name 有索引,只锁单行UPDATE user SET money=100 WHERE name='张三';
死锁日志里如果看到 LOCK_MODE: X, REC_NOT_GAP: nil 基本就是无索引导致。
死锁是偶发异常,重试就能成功,这是兜底方案。
Java 示例:
try { // 执行数据库操作} catch (SQLTransactionRollbackException e) { if (e.getMessage().contains("Deadlock")) { // 死锁异常,重试1-2次 retry(); }}
SHOW ENGINE INNODB STATUS; 看死锁详情死锁发生后MySQL自动回滚一个事务,无需手动干预;通过SHOW ENGINE INNODB STATUS查看原因;根治需固定访问顺序、加索引、短事务与代码重试;业务捕获死锁异常自动重试则可实现用户无感。