首页/数据/SQL 速查/并发失败重试模式
变更与事务52 条

并发失败重试模式

对死锁与序列化失败的标准处理:捕获特定错误、回滚、短暂退避后重试;重试需要幂等设计配合。

SQL 速查数据更新于 2026-10-13

并发失败后的重试模式

死锁与序列化失败不是异常,而是并发控制机制的正常输出:数据库检测到冲突后主动中止一方,让另一方继续。应用侧必须接住这类错误,回滚事务、短暂退避后重试整个事务。重试成立的前提是事务内的操作可重复执行——一旦事务里夹带了发消息、调外部接口这类不可回滚的副作用,重试就会造成重复执行,破坏业务数据。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
MySQL 可重试错误死锁与锁等待超时两类错误码
PostgreSQL 可重试错误序列化失败、死锁检出、锁不可用三类错误码
退避策略指数退避叠加随机抖动,避免所有客户端同时重试
必要条件业务操作可重复执行,或已用唯一约束与幂等键做了保证

典型使用场景

  • 库存扣减:并发下单时容易撞上锁冲突,重试是标准处理
  • 账务记账:两笔资金互转顺序不一致时的死锁处理
  • 定时批处理:批量更新遇到锁等待超时,退避后继续推进
  • 串行化隔离下的报表写入:冲突中止后自动重跑
  • 接口层统一封装:把重试逻辑收敛到一个事务模板里,避免各处重复实现

重试流程骨架

重试流程骨架
1. 开启事务
2. 执行读取与条件更新(带版本号或唯一键校验)
3. 提交事务

失败处理分支:
  捕获可重试错误(死锁 / 锁等待超时 / 序列化失败)
  回滚事务
  随机退避 10 到 200 毫秒后重试
  超过最大次数仍失败则向上抛出,由业务决定是否降级

必须遵守的两条:
  重试块内不包含不可回滚的外部副作用(发消息、扣外部额度)
  重试次数与退避时间都要有上限,避免重试风暴

错误码与处理方式

数据库错误类别含义处理
MySQL死锁错误码检测到循环等待,回滚代价较小的一方捕获后回滚重试
MySQL锁等待超时错误码等待时间超过阈值缩短事务或提高阈值后重试
PostgreSQL序列化失败串行化检测到危险结构必须整体重试事务
PostgreSQL死锁检出循环等待被打破捕获后回滚重试
PostgreSQL锁不可用锁定请求无法立即满足退避后重试或降级
重试必须从「事务开头」开始,不能在语句中间续跑:中止发生时事务上下文已经被破坏,继续使用同一连接上的状态会得到难以理解的错误。
统计重试次数很有价值:重试率突然上升通常意味着访问模式变了(批量任务时间调整、索引失效、热点行集中),它比平均耗时更早暴露问题。

易错点

  • 重试块里包含发送消息或调用外部接口,重试导致重复执行,业务出现重复流水
  • 重试没有上限或没有退避,高并发下形成重试风暴,反而把锁冲突放大
  • 只对死锁做了重试,漏掉序列化失败,串行化隔离下错误率居高不下
  • 从中断语句处续跑而不是重跑整个事务,事务上下文已失效,产生难排查的错误
  • 把锁等待超时一律当成数据库故障:多数情况是长事务或慢语句导致,应回到事务设计上解决

数据来源与参考

  • PostgreSQL Documentation · Serializable Isolation Level
  • MySQL 8.0 Reference Manual · Deadlocks
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌