死锁本身不扩散,但会引发连锁反应:长事务、mdl锁等导致等待堆积、连接池耗尽、接口超时;需通过show processlist和innodb_trx定位并kill钉子户事务,隔离ddl与dml,应用层加熔断重试。

数据库死锁本身不直接“扩散”,但会引发明显的连锁反应:一个死锁被检测并回滚后,若上游应用没做重试或错误处理,大量请求可能堆积在连接池、线程池或网关层;更常见的是,死锁常与长事务、未提交事务、MDL锁(元数据锁)或表级锁共存,导致其他正常事务持续等待,连接数飙升、接口超时、监控告警连环触发——这才是真正需要隔离的“故障面”。
快速切断阻塞源头
死锁只是症状,背后往往有“钉子户”事务在挡路:
- 立即执行 SHOW PROCESSLIST;,筛选状态为 Locked、Waiting for table metadata lock 或 Sending data 且 Time > 60秒 的线程,重点关注 User 非业务账号(如开发、测试、定时任务)的连接
- 运行 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60;,找出长时间未提交的事务,确认其 TRX_QUERY 是否合理、是否可安全终止
- 对确认无业务影响的线程,用 KILL [thread_id](不是 KILL QUERY),彻底释放其持有的所有锁和连接
阻断连接池雪崩
连接池满是死锁连锁反应最典型的外在表现,但根源不在池子大小:
- 应用侧需配置合理的 连接获取超时(如 HikariCP 的 connection-timeout)和 空闲连接最大存活时间,避免连接长期挂起
- 数据库侧检查 wait_timeout 和 interactive_timeout,确保空闲连接能及时断开,不占用资源
- 禁止在应用中手动管理 Connection 并长期 hold 不 close;所有数据库操作必须包裹在 try-with-resources 或显式 close 中
隔离高风险操作场景
某些操作天然容易诱发锁冲突,应从流程上物理隔离:
- DDL 与 DML 分离:ALTER TABLE、ADD INDEX 等操作必须避开业务高峰,并单独走发布通道,严禁混入日常事务流
- 批量导入/导出独立时段:Navicat 同步、mysqldump 备份等工具操作,应使用 --single-transaction(仅限 InnoDB)、关闭多线程、降低每批提交量,且安排在低峰期
- 报表类查询走只读副本:避免大范围 SELECT FOR UPDATE、GROUP BY + JOIN 扫描在主库执行,尤其不能与写事务共享同一连接
应用层加装“熔断+重试”防护
死锁异常(Deadlock found when trying to get lock)是唯一可预期、应主动捕获的数据库异常:
- 在 DAO 层统一拦截 MySQLTransactionRollbackException,识别死锁码(1213),触发 指数退避重试(如 100ms → 200ms → 400ms,最多 3 次)
- 对非幂等操作(如扣库存),重试前需校验前置状态(如查当前库存是否仍充足),避免重复扣减
- 将高频死锁事务标记为“敏感事务”,接入 Sentinel 或 Resilience4j 实现熔断降级,失败时返回兜底数据或友好提示,而非让整个接口不可用











