Spring Boot 中处理 MySQL 死锁需启用自动识别、退让与重试能力,通过添加 spring-retry 和 AOP 依赖、@EnableRetry 激活、@Retryable 精准捕获 DeadlockLoserDataAccessException 并配合 @Transactional 实现安全重试,同时强化幂等校验、避免副作用操作、配置 @Recover 兜底及优化 HikariCP 连接池参数。

在 Spring Boot 中处理 MySQL 死锁,核心不是“绕开”它,而是让系统具备自动识别、短暂退让、安全重试的能力。死锁本身是数据库的正常保护机制,关键在于业务层不崩溃、不重复执行、不丢失数据。
启用重试能力的基础配置
先确保项目具备重试能力:
- 添加依赖(无需指定版本,Spring Boot 3.x 默认兼容 spring-retry 1.3.x):
org.springframework.retry
spring-retry
org.springframework.boot
spring-boot-starter-aop - 在启动类或配置类上加 @EnableRetry 注解,激活声明式重试支持
- 死锁异常属于数据库访问异常,推荐捕获 DataAccessException 或更具体的 DeadlockLoserDataAccessException(Spring JDBC 提供)
用 @Retryable 精准拦截死锁并重试
把重试逻辑直接写在可能触发死锁的数据库操作方法上,保持业务干净:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 标注方法时指定只对死锁类异常重试,避免误重试其他严重错误:
@Retryable(
value = {DeadlockLoserDataAccessException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 200, multiplier = 2, maxDelay = 2000)
) - 延迟从 200ms 起步,倍数设为 2,最大不超过 2 秒——既避开竞争高峰,又不让用户长时间等待
- 务必搭配 @Transactional 使用,确保每次重试都在新事务中执行,否则会因事务已标记 rollback-only 而失败
保障重试过程安全可靠
重试不是简单地再跑一遍,必须守住幂等和一致性底线:
立即学习“Java免费学习笔记(深入)”;
- 所有写操作前加幂等校验:例如插入订单前查库确认 orderId 是否已存在;更新状态前检查当前状态是否允许变更
- 避免在重试方法内做非数据库副作用操作(如发短信、调外部接口),这些应放在重试成功后的独立回调或事件中
- 用 @Recover 定义兜底逻辑,比如记录告警、落库失败快照、触发人工介入流程,而不是静默吞掉异常
- 日志中明确打标死锁重试行为,例如:"Deadlock detected for order [{}], retry #{}, delay {}ms"
补充:连接池层面协同优化
重试生效的前提是数据库连接可用。建议同步检查 HikariCP 配置:
- 设置 connection-timeout: 5000(5秒内拿不到连接就快速失败,不卡主线程)
- 开启 validation-query: SELECT 1 和 test-on-borrow: true,避免拿到失效连接再触发死锁误判
- 适当调高 max-lifetime(如 30 分钟),减少连接老化引发的隐性竞争

















