幂等性设计三种模式:唯一键、状态机与去重表怎么选
幂等数据一致性订单同步库存同步API 编排
幂等为什么是集成的地基
跨系统数据同步中,网络超时、平台限流、下游宕机都会触发重试。如果写入操作不幂等,一次超时重试就可能造成重复下单、重复扣库存、重复记账——这类事故的资损远大于同步延迟。所谓幂等,就是同一操作执行一次和执行 N 次,业务结果完全一致。
模式一:唯一键约束
最朴素也最可靠的做法:给业务表加唯一索引(如 (platform, platform_order_no)),重复写入直接撞唯一约束,捕获冲突后转为更新或直接忽略。
- 优点:数据库兜底,代码再乱也不会产生脏数据;
- 缺点:只能防"重复插入",防不了"重复更新";分库分表下唯一键设计变复杂。
所有同步落库表都应以此作为底线,无论上层还做了什么。
模式二:状态机
适合有明确生命周期的单据(订单:已创建 → 已支付 → 已发货 → 已完成)。每次写入携带目标状态,更新时校验当前状态是否允许流转:
sql
UPDATE orders
SET status = 'SHIPPED', updated_at = NOW()
WHERE platform_order_no = 'TB20260001'
AND status IN ('PAID', 'SHIPPED'); -- 只允许从已支付流转;已是 SHIPPED 则空转
状态机天然幂等:重复推送同一状态,第二个请求命中空集,无副作用。它还能顺便拦截乱序事件(先收到"已发货"再收到"已支付"时,可按业务规则拒绝或排队)。
模式三:去重表
适合"事件流"场景:为每个事件分配唯一 ID,消费前先向去重表插入 (consumer, event_id),插入成功才继续处理,冲突说明已消费过。去重表要与业务写入在同一事务中,否则宕机窗口会出现"去重记录写了、业务没写"的假阳性。
三种模式怎么选
| 模式 | 防什么 | 适用场景 | 成本 |
|---|---|---|---|
| 唯一键约束 | 重复插入 | 一切落库写入(底线) | 极低 |
| 状态机 | 重复/乱序更新 | 订单、售后单等有生命周期的单据 | 中 |
| 去重表 | 重复消费事件 | MQ 消费、Webhook 推送 | 中 |
实践中三者是叠加而非互斥:去重表挡住重复事件,状态机约束流转,唯一键做最后兜底。轻易云的可视化集成方案中,每条数据流默认开启"按业务键幂等写入",并为订单类实体预置状态流转校验,接入方无需自行实现这套机制。
本文为原创内容,转载请注明出处:/insights/engineering/idempotency-design-patterns