1. 死锁现场:一次突如其来的生产事故
那天下午4点23分,我正在工位上悠闲地喝着咖啡,突然钉钉群里弹出一条消息:"下单接口又500了,而且是偶发性的,一会儿好一会儿坏。"看到"偶发"这个词,我后背一凉——这往往意味着最棘手的并发问题。
登录到Kibana查看错误日志,果然发现了那个熟悉的老朋友:
sql复制com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException:
Deadlock found when trying to get lock; try restarting transaction
这个错误在过去三个月里已经出现了17次,但今天的频率明显异常。更奇怪的是,我们的压测环境从未复现过这个问题。我立即打开了Grafana监控面板,发现死锁率从平时的0.01%飙升到了1.2%,而且集中在两个业务场景:
- 支付成功回调(高频操作)
- 定时任务清理超时订单(每小时执行)
提示:MySQL死锁错误通常伴随着"try restarting transaction"提示,这是InnoDB检测到死锁后自动回滚其中一个事务的保护机制。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 死锁原理与现场分析
2.1 InnoDB锁机制回顾
在深入分析前,我们需要理解几个关键概念:
- 行锁(Record Lock):锁定索引记录
- 间隙锁(Gap Lock):锁定索引记录之间的间隙
- Next-Key Lock:行锁+间隙锁的组合
- X锁(排他锁):写锁,其他事务不能获取任何锁
- S锁(共享锁):读锁,其他事务可以获取S锁
MySQL默认的REPEATABLE READ隔离级别下,更新操作会获取Next-Key Lock,除非查询使用了唯一索引。
2.2 死锁现场还原
通过SHOW ENGINE INNODB STATUS命令,我们抓取到了最新的死锁信息:
sql复制LATEST DETECTED DEADLOCK
------------------------
*** (1) TRANSACTION:
TRANSACTION 598474, ACTIVE 0 sec starting index read
UPD
