幂等性设计核心是“执行即收敛”,而非拒绝重复:①用唯一业务标识+数据库唯一约束兜底;②redis token实现请求级预检;③状态机+条件更新控制流程跃迁;④幂等键+缓存标记做轻量去重。

幂等性设计不是让方法“拒绝重复”,而是让重复调用的结果与单次调用完全一致——状态不翻倍、资金不 double 扣、订单不重复生成。关键不在拦截,而在“执行即收敛”。
用唯一业务标识 + 数据库唯一约束兜底
这是最直接、最可靠的落地方式。核心是把“不可重复”这件事交给数据库的原子性和唯一索引来保证。
- 为每次操作绑定一个全局唯一且业务可识别的标识,比如订单创建用 orderNo、支付用 payId、退款用 refundNo
- 在对应业务表上建立唯一索引(如
UNIQUE KEY (order_no)),而不是仅靠代码判断 - 插入时直接尝试写入主业务记录(如订单表),成功则继续后续逻辑;失败捕获
DataIntegrityViolationException,说明已存在,直接返回成功或已有结果 - 注意:该方式适用于“创建型”操作,且唯一标识必须由客户端或网关统一分配(避免服务端生成导致重试时 ID 不一致)
用 Redis Token 实现请求级原子预检
适合表单提交、按钮点击等用户主动触发场景,本质是“先占坑,再干活”,确保同一 Token 只能被消费一次。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 前端在加载页面时,调用
/token接口获取一个短期有效 Token(如 5 分钟),存入表单 hidden 字段 - 提交时携带该 Token,后端用
SETNX key value EX expire尝试写入 Redis,key 为 Token 值,value 可设为请求时间戳或 traceId - 若 SETNX 返回 true,说明首次处理,继续执行业务;若返回 false,直接返回“重复提交”提示
- 务必在业务逻辑执行成功后才删除 Token 或标记为已使用——不能提前删,否则可能因异常导致漏判
用状态机 + 条件更新控制流程跃迁
对有明确生命周期的业务(如订单、工单、审批),幂等的关键不是“防重复”,而是“只允许合法状态转移”。
- 定义清晰的状态流转图,例如:INIT → PAYING → PAID → SHIPPED,禁止从 INIT 直接跳到 SHIPPED
- 更新操作带前置条件,如更新订单状态时写:
UPDATE order SET status = 'PAID' WHERE id = ? AND status = 'PAYING' - 检查 SQL 影响行数:若影响 0 行,说明当前状态不满足跃迁条件(可能是已支付、或还在待支付),直接返回当前状态,不抛错也不重试
- 配合乐观锁(version 字段)可进一步防止并发覆盖,但需注意 version 冲突应视为正常业务分支,而非系统异常
用幂等键 + 缓存标记做轻量级去重
适用于高频、低一致性要求、或作为前几层防护的补充手段,比如日志上报、通知触发、积分累加等。
- 构造幂等键,格式建议为:
businessType:userId:action:timestampTruncated(如notify:10086:sms:202607) - 操作前用
SET key "1" NX EX 3600写入 Redis,设置合理过期时间(避免长期占用) - 成功则执行;失败则跳过或返回缓存结果(如通知已发,不再重复推送)
- 慎用于资金类操作——Redis 故障或网络分区时可能失效,必须搭配数据库最终一致性校验
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










