举一个幂等性在工程场景中的案例
除了之前提到的分布式系统、HTTP协议和数据库更新这里为你补充一个极具代表性且容易出错的工程场景案例‌第三方支付回调Webhook处理‌。案例背景支付成功后的库存扣减与订单状态更新在电商或金融系统中当用户完成支付后第三方支付平台如支付宝、微信支付、Stripe会向你的服务器发送一个异步通知Callback/Webhook告知支付结果。为什么这个场景非幂等会出大问题‌重试机制‌第三方平台为了保证通知必达通常采用“至少一次”投递策略。如果你的服务器因为网络波动、GC停顿或逻辑错误没有及时返回 SUCCESS 响应第三方平台会在短时间内如5s、10s、30s…多次重发同一个支付成功的通知。‌业务后果‌‌重复发货‌如果接口非幂等每次收到通知都触发发货逻辑会导致用户付一笔钱仓库发多次货。‌重复积分/优惠券发放‌用户获得多倍积分或多次使用同一张优惠券。‌数据状态混乱‌订单状态可能从“已支付”被错误地再次流转引发后续对账异常。工程落地方案基于“状态机 唯一索引”的双重保障在这个场景中最稳健的幂等实现不是靠前端Token因为回调是第三方发起的无法控制前端而是依靠后端的数据状态约束。‌核心逻辑流程‌‌接收回调‌服务端接收到第三方支付平台的回调请求包含 out_trade_no商户订单号和 transaction_id第三方交易流水号。‌验签‌首先验证签名确保请求确实来自合法的第三方平台防止伪造请求。‌幂等校验与执行原子操作‌利用数据库的唯一索引或乐观锁确保“订单状态从待支付变为已支付”这个动作只能成功一次。‌代码逻辑示意Java MySQL‌javaTransactionalpublic void handlePaymentCallback(String outTradeNo, String transactionId) {// 1. 查询当前订单状态Order order orderMapper.selectByOutTradeNo(outTradeNo);// 2. 状态机判断只有“待支付”状态才允许处理 if (!OrderStatus.PENDING.equals(order.getStatus())) { // 如果订单已经是“已支付”或“已关闭”直接返回成功 // 这就是幂等性的体现多次调用结果一致不执行后续逻辑直接告诉第三方我收到了 log.info(订单 {} 已处理过状态为: {}, outTradeNo, order.getStatus()); return; } // 3. 执行业务逻辑更新状态、扣减库存、增加积分 // 关键点使用乐观锁或条件更新确保并发安全 int affectedRows orderMapper.updateStatusAndPayInfo( outTradeNo, OrderStatus.PAID, transactionId, order.getVersion() // 乐观锁版本号 ); if (affectedRows 0) { throw new BusinessException(更新失败可能存在并发冲突或订单状态已变更); } // 4. 执行后续副作用操作如发送发货消息到MQ messageProducer.send(new DeliveryMessage(outTradeNo));}‌对应的SQL更新语句乐观锁实现‌sqlUPDATE ordersSET status ‘PAID’,pay_transaction_id #{transactionId},version version 1WHERE out_trade_no #{outTradeNo}AND status ‘PENDING’ – 关键只更新处于待支付状态的订单AND version #{version};3. 方案解析‌第一道防线状态判断‌代码中先检查 status ! PENDING。如果第三方第一次回调成功将状态改为 PAID第二次回调进来时发现状态已是 PAID直接返回成功不执行任何业务逻辑。这保证了‌业务结果的幂等性‌。‌第二道防线数据库约束‌即使在高并发下两个回调请求同时进入代码并通过了状态检查UPDATE 语句中的 AND status ‘PENDING’ 条件确保了只有一个请求能更新成功受影响行数为1另一个请求受影响行数为0从而抛出异常或视为重复处理。这保证了‌数据层面的幂等性‌。‌第三道防线唯一索引兜底‌可以在支付流水表中将 transaction_id第三方交易号设为唯一索引。如果尝试插入两条相同的第三方支付记录数据库会直接报错从最底层杜绝重复记账。4. 总结在支付回调场景中幂等性的核心不在于“拦截请求”而在于‌“识别并忽略已处理的状态”‌。通过‌状态机模式‌配合‌数据库原子更新‌可以确保无论第三方平台重发多少次通知你的系统只会执行一次发货、一次积分增加最终状态始终一致。这是分布式系统中处理外部不可控重试最经典的幂等实践。