分布式事务异常时的“冲正”是业务层基于快照数据执行的幂等、可重试补偿操作,需按Saga逆序执行,失败后自动重试并兜底人工介入。

分布式事务中遇到异常时,触发“冲正”操作,本质是执行预定义的补偿逻辑,把已提交的本地事务逆向回滚。这不是数据库层面的自动回滚,而是业务层主动发起的反向操作,关键在于设计可预测、可控制、可验证的补偿行为。
补偿逻辑必须自带幂等与可重试能力
一旦原始操作成功(如扣款),补偿动作(如退款)就可能被多次调用——网络超时重发、死信队列重试、人工干预等都会导致重复触发。因此:
- 每个补偿方法需以唯一业务标识(如订单号+操作类型)为幂等键,写入状态表或利用数据库唯一索引拦截重复执行;
- 补偿本身不能依赖外部不稳定服务(如调第三方短信接口),若必须依赖,该依赖环节也得封装重试和降级(如超时后跳过通知,仅保证资金状态正确);
- 避免在补偿里做条件判断或读取实时业务状态再决策,应基于原始事务日志中的快照数据执行,确保结果确定。
失败链路要明确补偿范围与顺序
Saga 模式要求按“正向执行顺序的逆序”执行补偿。比如一个下单 Saga 包含:创建订单(T1)→ 扣减库存(T2)→ 扣减账户(T3)。若 T3 失败,只补偿 T2 和 T1;若 T2 失败,则只补偿 T1。不能跳过中间步骤,也不能反向遗漏。
实现上需在事务编排器中维护已成功步骤的有序列表,并在异常捕获点立即冻结该列表,作为后续补偿调度的依据。协同模式下则靠事件溯源记录每步完成状态,按时间倒序扫描并触发对应 Cn 方法。
补偿失败必须有兜底路径,不能静默丢弃
退钱接口持续超时、用户账户被司法冻结、补偿SQL因字段变更报错……这些真实场景中,补偿本身也会失败。此时不能停留在“已告警、待处理”状态:
- 自动进入死信队列或写入补偿失败表,带失败原因、原始参数、时间戳、重试次数;
- 由独立定时任务拉取失败记录,按指数退避策略持续重试(如 1s → 3s → 9s);
- 超过阈值(如 24 小时仍失败)自动升为人工介入工单,附带完整上下文(原始请求、各服务响应、日志 ID、补偿尝试轨迹);
- 所有补偿入口统一接入监控埋点,失败率、平均耗时、重试分布需实时可视。
变量操作需从“过程态”转为“结果态”建模
常见误区是把补偿写成“undo amount += 100”,这隐含了当前余额可变、状态未锁定的前提。实际应改为“ensure balance after refund = original_balance + 100”,即基于事务日志中记录的原始快照值做确定性还原。
例如:T1 扣款前余额为 500,日志记下 snapshot={userId:1001, preBalance:500, amount:100}。补偿 C1 不查当前余额再加 100,而是直接执行 update account set balance = 500 where user_id = 1001 and balance != 500 —— 这样既幂等,又规避了并发更新干扰。

















