核心概念:什么是幂等性
同一个请求无论执行多少次,最终结果完全一致。典型场景:用户支付时网络卡顿重复点击按钮,后台接收多个请求,仅扣一次钱、生成一个订单。
5 种幂等性设计方案(附优缺点 + 适用场景)
方案 1:数据库唯一索引【初级|最简单粗暴】
实现 :订单表对订单号加唯一索引,插入重复订单号时数据库直接报错,后端捕获异常并返回「订单已存在」。
优点:实现简单、数据库天然支持,无额外代码开发;
缺点:仅防插入重复,无法处理更新操作的幂等;抛异常处理,性能稍差;
适用场景:订单创建、用户注册、商品上架等纯插入操作。
方案 2:Token 机制【中级|防前端重复提交】
实现:
①用户打开支付页,后端生成唯一 Token 存入 Redis(设 5 分钟过期)并返回前端;
②前端提交支付请求时携带 Token;
③后端通过Lua 脚本原子性完成「Redis 查 Token + 存在则删除」,删除成功则处理业务,否则返回「请勿重复提交」。
核心:查询 + 删除必须原子性,避免高并发下的并发问题;
优点:通用性极强,可适配绝大多数场景;
缺点:需要前端配合传参;强依赖 Redis,Redis 宕机则失效;
适用场景:表单提交、评论发布、支付发起等需要前端配合防用户重复点击的场景。
方案 3:分布式锁【中级|高并发防重复】
实现 :以订单号 / 用户 ID + 业务标识为锁的 Key,基于 Redis 实现分布式锁;
①加锁时生成唯一标识 + 设置 30 秒过期时间;
②加锁失败则返回「操作进行中,请稍后」;
③加锁成功处理业务,处理完成后通过 Lua 脚本判断并删除自身持有的锁;
核心:规避分布式锁 3 大坑(过期时间、误删别人的锁、锁释放);
优点:通用性强,能有效防高并发重复请求;
缺点:性能稍差,依赖 Redis;
适用场景 :支付扣钱、库存扣减、优惠券领取等需要严格防并发的操作。
方案 4:状态机 + 乐观锁【高级|最优解】
实现:基于业务状态流转实现,如订单状态:待支付→支付中→已支付 / 支付失败
①支付请求到达后,先判断订单当前状态;
②通过数据库乐观锁原子性更新状态(SQLWhere 条件带「当前状态 + 版本号」),仅当状态为「待支付」且版本号匹配时更新为「支付中」;
③更新成功则处理业务,失败则返回「订单已处理」。
核心:状态流转的原子性,由数据库乐观锁保证;
优点:不依赖任何外部组件,逻辑清晰贴合业务语义,性能优;
缺点 :仅适用于有明确状态流转的业务;
适用场景:订单支付、工单处理、审批流、物流状态更新等有固定状态的业务。
方案 5:全局唯一 Request ID【架构级|最严谨】
实现:
①前端 / 网关生成全局唯一 Request ID,所有请求均携带该 ID;
②后端收到请求后,通过 Redis 的setnx 命令原子性标记「该 ID 正在处理」;
③标记失败则返回「请求处理中」,标记成功则处理业务;
④处理完成后将结果缓存至 Redis,后续重复请求直接返回缓存结果;
核心:setnx 天然保证原子性,仅第一个请求能标记成功;需做好结果缓存和过期策略;
优点 :最严谨,适配所有场景的幂等性,可返回历史处理结果;
缺点:实现复杂,需开发结果缓存逻辑;要求 Request ID 全局唯一且无冲突;
适用场景 :支付转账、资金划拨、交易清算等核心高敏感业务(对幂等性要求极致的场景)。
方案选择指南(快速匹配业务)
- 纯插入操作→数据库唯一索引(最简单);
- 前端用户重复点击→Token 机制(适配性强);
- 高并发防重复处理→分布式锁(性能与可靠性平衡);
- 有状态流转的业务→状态机 + 乐观锁(最优雅,贴合业务);
- 核心高敏感业务→全局唯一 Request ID(最严谨,零容错)。
必避坑点(面试高频)
- 分布式锁:必须设置合理过期时间,通过 Lua 脚本保证「删锁原子性」,防止误删其他请求的锁;
- Token 机制:查询 + 删除必须原子性,严禁分两步操作,避免高并发下重复处理;
- 状态机:必须用乐观锁(版本号 / 当前状态) 保证状态更新原子性,杜绝多请求同时修改状态;
- 全局 Request ID:做好缓存结果的过期策略,避免 Redis 内存溢出;保证 Request ID 的全局唯一性(如雪花算法)。
面试加分项
1. 结合实战案例回答
例:公司支付接口采用「Token 机制 + 状态机 + 唯一索引」组合方案:
①前端通过 Token 防重复点击;
②订单表以订单号做唯一索引,防重复插入;
③通过状态机 + 乐观锁控制支付状态流转,确保仅一次支付成功,上线后彻底解决重复下单问题。
2. 延伸 MQ 消息幂等性
MQ 消息可能因网络问题重复投递,消费者需保证幂等:
- 方案 1:基于消息 ID 做 Redis 去重,消费前先判断消息 ID 是否处理过;
- 方案 2:业务层天然幂等,如扣减库存时 SQL 加条件「where 库存 > 0」,重复扣减时直接失败。
3. 核心总结
幂等性是分布式系统的基本功,并非简单加锁即可解决;实际开发中需结合业务场景组合方案 ,而非单一使用,核心原则是:保证请求处理的原子性,杜绝重复执行带来的脏数据。