企业级 Java 后端实战:Spring Boot + MyBatis 实现幂等下单接口
【摘要】 本文介绍企业级 Java 下单接口的幂等落地方案:前端防抖、幂等 Token 与数据库唯一索引分层设防,含 Spring Boot + MyBatis 核心代码、建表要点与验收用例。
本文以一个企业级下单接口为例,介绍如何用 Spring Boot + MyBatis 落地接口幂等。文中出现的金额、并发数、超时时间等均为示例数值,请按实际业务调整,切勿直接照抄到生产配置。
一、为什么下单接口需要幂等
用户点击提交后网络抖动、前端重复点击、网关自动重试,都可能让同一笔订单被创建两次。幂等的含义是:同一个请求被执行多次,与执行一次的效果相同。对下单、支付、退款这类涉及资金的接口,幂等不是可选项,而是上线前必须通过的验收项。
二、三种常见方案对比
| 方案 | 适用场景 | 主要缺点 |
|---|---|---|
| 前端防抖 + 提交锁 | 防用户手抖重复点击 | 防不住网络重试和网关重发 |
| 幂等 Token | 下单、支付等写操作 | 需要额外存储 Token,流程稍复杂 |
| 数据库唯一索引 | 所有写操作 | 只能兜底,报错后需要业务层再做友好处理 |
生产上通常把三者组合使用:前端防抖挡住大部分重复,Token 做主防线,唯一索引做最后一道兜底。
三、落地方案:Token + 唯一索引双保险
流程如下:
- 用户进入下单页,后端发放一个一次性幂等 Token,示例 TTL 为 15 分钟(示例数值)。
- 提交订单时前端把 Token 放在请求头
Idempotency-Key中一起发送。 - 服务端先校验并删除 Token:Token 不存在或已使用,直接返回首次执行的结果。
- 写入订单时,订单号字段建唯一索引,即使 Token 校验被绕过也不会产生重复订单。
四、核心代码
1. 校验 Token 的拦截器
@Component
public class IdempotencyInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String key = request.getHeader("Idempotency-Key");
if (key == null || key.isBlank()) {
throw new IllegalArgumentException("缺少幂等键 Idempotency-Key");
}
// 原子删除:删成功说明是首次请求,删失败说明已处理过
Boolean first = redisTemplate.delete("idem:" + key);
if (Boolean.FALSE.equals(first)) {
throw new DuplicateRequestException("请求已处理,请勿重复提交");
}
return true;
}
}
2. 下单服务:唯一索引兜底
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Transactional(rollbackFor = Exception.class)
public Order createOrder(OrderCreateRequest req) {
Order order = new Order();
// 订单号由业务规则生成,例如日期 + 序列,库表上建唯一索引
order.setOrderNo(generateOrderNo());
// 示例:订单金额 99.00 元为示例数值,实际金额以后端按商品与优惠规则计算为准
order.setAmount(req.getAmount());
order.setStatus(OrderStatus.CREATED);
orderMapper.insert(order);
return order;
}
}
对应的建表语句要点:
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(32) NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(16) NOT NULL,
UNIQUE KEY uk_order_no (order_no)
);
五、测试与验收
上线前建议至少覆盖这三个用例(括号内为示例数值):
- 同一个 Token 连续提交 5 次,只生成 1 笔订单,其余请求返回首次执行的结果。
- 并发测试:示例并发 200(示例数值)下压测下单接口,订单数与请求去重后一致,无重复订单。
- Token 过期测试:Token 超过示例 TTL 15 分钟(示例数值)后提交,接口应明确拒绝,而不是静默成功。
六、容易踩的坑
- 只做前端防抖:网络层和网关的重试前端看不到,服务端必须有自己的防线。
- Token 校验与写库不在同一事务边界内考虑:校验通过后进程崩溃,Token 已删、订单未落库,重试会被误判为重复,关键业务要做好对账补偿。
- 忘记建唯一索引:Token 机制一旦出问题,没有任何兜底。
- 幂等键粒度不当:按“用户 + 商品”做键会误拦截用户正常买两件同款;按“一次提交”生成唯一键才合理。
七、总结
企业级后端做幂等,核心思路是分层设防:前端防抖减少重复,幂等 Token 做主防线,数据库唯一索引做最终兜底,再配上过期测试和对账补偿。把这些做到位,下单接口才能在网络抖动和重试面前保持“只建一单”的承诺。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)