ITPub博客

首页 > 应用开发 > Java > 接口幂等设计:从重试到数据一致性

接口幂等设计:从重试到数据一致性

原创 Java 作者:wt1179020102 时间:2026-07-30 11:23:54 0 删除 编辑

接口幂等设计:从重试到数据一致性

在日常后端开发中,我们经常会遇到这样的问题:用户只点击了一次按钮,但前端因为网络超时发起了重试;消息队列只希望消费一次,但实际投递了两次;第三方支付平台回调通知多次到达。如果服务端没有做好幂等控制,一次正常请求就可能变成重复创建订单、重复扣减库存、重复发放权益。

所谓接口幂等,简单来说就是:同一个业务请求执行一次和执行多次,最终结果应该一致。它不是为了阻止所有重复请求,而是让重复请求不会造成重复副作用。

哪些接口需要幂等

并不是所有接口都必须做复杂的幂等设计。一般来说,读接口天然幂等,例如查询订单详情、查询用户信息。真正需要重点关注的是会修改数据的接口,例如:

  • 创建订单
  • 支付回调
  • 扣减库存
  • 发放优惠券
  • 提交表单
  • 消息消费处理

这些场景都有一个共同点:一旦重复执行,业务结果可能发生变化。因此,设计接口时不能只考虑“正常请求”,还要考虑“同一个请求重复到达”。

常见方案一:唯一业务键

最直接的方式是使用业务唯一键。例如创建订单时,可以由前端或服务端生成一个 requestId,同一次提交始终携带同一个值。服务端把这个值和业务数据一起落库,并建立唯一索引。

CREATE TABLE order_request (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  request_id VARCHAR(64) NOT NULL,
  user_id BIGINT NOT NULL,
  order_id BIGINT NOT NULL,
  created_at DATETIME NOT NULL,
  UNIQUE KEY uk_request_id (request_id)
);

当重复请求到达时,数据库唯一索引会拦截重复写入。服务端捕获唯一键冲突后,可以查询之前生成的订单并返回相同结果。

这种方式简单可靠,特别适合创建类接口。需要注意的是, requestId 必须和具体业务绑定,不能被不同业务场景复用。

常见方案二:状态机控制

有些业务不是简单的新增数据,而是状态流转,例如订单支付:

待支付 -> 支付中 -> 已支付 -> 已完成

这类场景可以通过状态机保证幂等。例如支付回调到达时,只允许 待支付 或 支付中 的订单更新为 已支付,如果订单已经是 已支付,则直接返回成功。

UPDATE orders
SET status = 'PAID', paid_at = NOW()
WHERE order_no = ?
  AND status IN ('WAIT_PAY', 'PAYING');

执行后判断影响行数。如果影响行数为 1,说明本次完成了状态变更;如果影响行数为 0,则说明订单可能已经处理过,再查询订单状态确认即可。

这种方案的优点是逻辑清晰,尤其适合支付、审核、发货、退款等有明确状态流转的业务。

常见方案三:幂等记录表

对于消息消费或第三方回调,也可以单独维护一张幂等记录表。每次处理前先写入一条处理记录,处理完成后更新状态。

CREATE TABLE idempotent_record (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  biz_type VARCHAR(32) NOT NULL,
  biz_key VARCHAR(128) NOT NULL,
  status VARCHAR(16) NOT NULL,
  created_at DATETIME NOT NULL,
  updated_at DATETIME NOT NULL,
  UNIQUE KEY uk_biz (biz_type, biz_key)
);

其中 biz_type 表示业务类型,例如 PAY_CALLBACK; biz_key 表示唯一业务编号,例如支付平台流水号。这样即使不同业务使用相同编号,也不会互相影响。

处理流程可以设计为:

  1. 插入幂等记录,状态为 PROCESSING
  2. 执行业务逻辑
  3. 更新记录状态为 SUCCESS
  4. 重复请求到达时,先检查记录状态,再决定返回结果或稍后重试

这种方案比单纯依赖业务表更通用,适合复杂业务流程。

需要避免的几个坑

第一,不要只依赖前端按钮置灰。前端体验优化很有必要,但它不能替代服务端幂等。用户刷新页面、网络重试、接口被重复调用,服务端都必须能兜住。

第二,不要把幂等键设计得太宽泛。例如只用 user_id 作为唯一键,会导致同一个用户无法提交第二笔正常订单。幂等键应该标识“同一次业务请求”,而不是标识用户本身。

第三,不要忽略并发请求。两个相同请求可能几乎同时到达,如果只是在代码里先查询再插入,就会出现并发漏洞。更稳妥的方式是配合数据库唯一索引、事务或原子更新。

第四,幂等记录需要设置合理的保存周期。并不是所有记录都要保存,可以根据业务特点保留 7 天、30 天或更长时间。但支付、账务类数据通常需要更谨慎。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70050981/viewspace-3177208/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2026-07-30

  • 博文量
    3
  • 访问量
    2891