# 订单激活幂等性修复 - 设计 ## 目标 1. 同一订单被重复支付/重复回调/重复请求时,只会激活一次套餐使用记录。 2. 重复请求返回“幂等成功”(不报错,不重复激活)。 3. 避免因并发导致的重复插入。 ## 方案 ### 1) 以状态机作为幂等门闸 将订单支付状态从 `pending` 变更为 `paid` 时使用条件更新: - `UPDATE tb_order SET payment_status=paid,... WHERE id=? AND payment_status=pending` - 若 `RowsAffected == 0`: - 视为订单已被处理(可能已支付/已取消/已退款) - 对“已支付”场景直接返回成功(幂等成功) - 对“非待支付且非已支付”场景返回对应业务错误(例如已取消不允许支付) 这样可以确保并发下只有一个请求能“拿到激活资格”。 ### 2) 激活逻辑只在首次成功支付后执行 `activatePackage` 只在上述条件更新成功后执行;并确保激活过程内的数据读取使用同一个事务 `tx`(避免出现读取不一致或部分写入)。 ### 3) 防御性约束(可选但推荐) 为 `tb_package_usage` 增加唯一约束(示例): - 同一订单下,同一 `package_id` 只能有一条 usage - 以 `order_id + package_id` 为主(按当前业务:一个订单对应一个资源,且一次购买不应重复同套餐) 如果未来允许同订单同套餐多份购买,则需要同时引入 `quantity` 或 usage 的明细拆分策略,再调整唯一约束。 ## 验收标准 - 重复调用钱包支付/支付回调接口,不会重复生成 `tb_package_usage` 记录。 - 幂等重复请求返回成功。 - 新增测试通过。