应用侧锁错误处理是什么
数据库的锁错误在应用层必须有明确策略:1213(死锁,事务被回滚)与 1205(锁等待超时)都属于「重试就可能成功」的错误,前提是整个事务可重放且业务幂等;而 1062(唯一键冲突)这类语义错误重试没有意义。做法是把重试放在事务边界外,带上有界次数与随机退避,超过上限就告警并抛出,避免风暴期把数据库压垮。
基本信息
| 可重试错误 | 1213 死锁被回滚、1205 锁等待超时 |
|---|---|
| 不可重试 | 1062 唯一键冲突、1146 表不存在等语义错误 |
| 重试边界 | 整个事务从 BEGIN 开始重做,不能只重试单条语句 |
| 重试策略 | 有界次数(如 3 次)+ 指数退避 + 随机抖动 |
| 前置条件 | 事务内操作幂等或可安全重放 |
| 相关参数 | innodb_lock_wait_timeout 控制等待上限 |
典型使用场景
- 秒杀或抢单场景:热点行并发更新频繁产生死锁,需要自动重试吸收
- 批量任务并发写同一批记录:偶发锁超时不应直接失败
- 订单状态流转:多表更新顺序不一致时死锁概率上升
- 数据同步与补偿任务:重试是常态,需保证重复执行结果一致
- 故障降级评估:重试上限与告警阈值决定系统在锁风暴中的行为
重试伪代码
重试伪代码
for attempt in 1..3:
try:
BEGIN
...业务写入...
COMMIT
break
except Deadlock(1213) or LockWaitTimeout(1205):
ROLLBACK
sleep(50ms * attempt + random(0..30ms)) # 退避加抖动,避免同步重试
except OtherError as e:
raise e # 语义错误不重试,直接上报
# 超过次数:记录上下文并告警,避免无限重试确认加锁范围与超时设置
确认加锁范围与超时设置
-- 事务内实际锁了多少行,行数大说明条件没走索引
SELECT trx_id, trx_state, trx_rows_locked, trx_rows_modified, LEFT(trx_query, 80)
FROM information_schema.INNODB_TRX ORDER BY trx_rows_locked DESC;
-- 单会话放宽等待时间(批处理场景)
SET SESSION innodb_lock_wait_timeout = 120;
-- 查最近一次死锁涉及的事务与语句
SHOW ENGINE INNODB STATUS\G # 只看 LATEST DETECTED DEADLOCK 段错误码与处置
| 错误码 | 含义 | 处置方式 |
|---|---|---|
| 1213 | 死锁,InnoDB 回滚了事务 | 整事务重试,通常一次即可成功 |
| 1205 | 锁等待超时 | 重试或延长等待时间,同时排查长事务 |
| 1062 | 唯一键冲突 | 业务语义问题,不重试,按业务规则处理 |
| 1206 | 锁表数量上限 | 事务过大,需拆分批次 |
| 3572 | 并发 DDL 与 DML 冲突 | 错峰执行结构变更 |
退避要加随机抖动:固定间隔重试会让所有失败请求在同一时刻再次冲击同一行,把瞬时冲突变成持续冲突;有界重试配合告警,才能在风暴期保留人工介入的入口。
只有在事务内所有操作可安全重放(幂等)时才允许自动重试:如果事务里包含扣减库存、发送消息等不可回滚的外部副作用,重试会造成重复扣减或重复通知。