news 2026/7/14 7:34:43

外卖CPS场景下Java后端接口幂等性设计的多种实现技巧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
外卖CPS场景下Java后端接口幂等性设计的多种实现技巧

外卖CPS场景下Java后端接口幂等性设计的多种实现技巧

在外卖CPS(Cost Per Sale)系统中,用户下单、佣金结算等关键接口常因网络超时、客户端重试等原因被重复调用。若未做幂等处理,将导致重复创建订单、多发奖励等严重问题。本文结合实际业务场景,介绍基于Token、数据库唯一约束、分布式锁等多种幂等实现方式,并提供可落地的Java代码示例。

1. 基于请求唯一ID的数据库幂等表

最通用的方式是使用request_id作为幂等键,在业务执行前校验是否已处理:

packagebaodanbao.com.cn.cps.idempotent;importorg.springframework.jdbc.core.JdbcTemplate;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;@ServicepublicclassIdempotentService{privatefinalJdbcTemplatejdbcTemplate;publicIdempotentService(JdbcTemplatejdbcTemplate){this.jdbcTemplate=jdbcTemplate;}@TransactionalpublicbooleantryAcquire(StringrequestId){StringcheckSql="SELECT 1 FROM idempotent_record WHERE request_id = ?";Integerexists=jdbcTemplate.queryForObject(checkSql,Integer.class,requestId);if(exists!=null){returnfalse;// 已处理}StringinsertSql="INSERT INTO idempotent_record(request_id, create_time) VALUES (?, NOW())";jdbcTemplate.update(insertSql,requestId);returntrue;}}

对应建表语句:

CREATETABLEidempotent_record(request_idVARCHAR(64)NOTNULLPRIMARYKEY,create_timeDATETIMENOTNULL);

在CPS下单接口中使用:

packagebaodanbao.com.cn.cps.order;importbaodanbao.com.cn.cps.idempotent.IdempotentService;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestHeader;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassCpsOrderController{privatefinalIdempotentServiceidempotentService;privatefinalOrderServiceorderService;publicCpsOrderController(IdempotentServiceidempotentService,OrderServiceorderService){this.idempotentService=idempotentService;this.orderService=orderService;}@PostMapping("/cps/order/create")publicOrderResultcreateOrder(@RequestBodyCreateOrderRequestreq,@RequestHeader("X-Request-ID")StringrequestId){if(!idempotentService.tryAcquire(requestId)){returnorderService.queryOrderByRequestId(requestId);// 返回已有结果}returnorderService.createOrder(req);}}

2. 基于Redis的幂等令牌机制

适用于高并发场景,利用Redis的原子性操作实现快速校验:

packagebaodanbao.com.cn.cps.idempotent.redis;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Component;importjava.util.concurrent.TimeUnit;@ComponentpublicclassRedisIdempotentToken{privatefinalStringRedisTemplateredisTemplate;publicRedisIdempotentToken(StringRedisTemplateredisTemplate){this.redisTemplate=redisTemplate;}publicbooleanacquire(Stringkey,longexpireSeconds){Booleanresult=redisTemplate.opsForValue().setIfAbsent(key,"1",expireSeconds,TimeUnit.SECONDS);returnBoolean.TRUE.equals(result);}}

配合前端预获取Token:

@PostMapping("/cps/order/token")publicStringgenerateToken(){Stringtoken="token_"+System.currentTimeMillis()+"_"+Thread.currentThread().getId();// 默认5分钟有效redisIdempotentToken.acquire(token,300);returntoken;}@PostMapping("/cps/order/create-with-token")publicOrderResultcreateOrderWithToken(@RequestBodyCreateOrderRequestreq,@RequestHeader("X-Idempotent-Token")Stringtoken){// 注意:此处不再主动acquire,而是检查是否存在Booleanexists=redisTemplate.hasKey(token);if(Boolean.FALSE.equals(exists)){thrownewIllegalArgumentException("Invalid or expired token");}// 执行业务并删除token(防止重用)OrderResultresult=orderService.createOrder(req);redisTemplate.delete(token);returnresult;}

3. 利用数据库唯一索引实现天然幂等

对于“用户+活动”维度的奖励发放,可直接在业务表上建立联合唯一索引:

CREATETABLEuser_reward(idBIGINTPRIMARYKEYAUTO_INCREMENT,user_idVARCHAR(32)NOTNULL,activity_idVARCHAR(32)NOTNULL,reward_amountDECIMAL(10,2)NOTNULL,UNIQUEKEYuk_user_activity(user_id,activity_id));

Java层捕获异常即可:

packagebaodanbao.com.cn.cps.reward;importorg.springframework.dao.DuplicateKeyException;publicclassRewardService{publicvoidgrantReward(StringuserId,StringactivityId,doubleamount){try{rewardMapper.insert(userId,activityId,amount);}catch(DuplicateKeyExceptione){// 幂等:已发放过,可查询并返回原记录return;}}}

4. 分布式锁兜底方案

当上述方法不适用时(如无明确唯一键),可采用Redisson分布式锁:

packagebaodanbao.com.cn.cps.idempotent.lock;importorg.redisson.api.RLock;importorg.redisson.api.RedissonClient;importorg.springframework.stereotype.Component;@ComponentpublicclassDistributedIdempotentLock{privatefinalRedissonClientredissonClient;publicDistributedIdempotentLock(RedissonClientredissonClient){this.redissonClient=redissonClient;}public<T>TexecuteWithLock(StringlockKey,java.util.concurrent.Callable<T>task){RLocklock=redissonClient.getLock(lockKey);try{if(lock.tryLock(1,10,TimeUnit.SECONDS)){returntask.call();}else{thrownewRuntimeException("Failed to acquire idempotent lock");}}catch(Exceptione){thrownewRuntimeException(e);}finally{if(lock.isHeldByCurrentThread()){lock.unlock();}}}}

调用示例:

StringlockKey="idempotent:order:"+req.getUserId()+":"+req.getActivityId();returndistributedIdempotentLock.executeWithLock(lockKey,()->{// 查询是否已存在订单Orderexisting=orderMapper.selectByUserAndActivity(...);if(existing!=null)returnexisting;returnorderMapper.insertNewOrder(req);});

本文著作权归 俱美开放平台 ,转载请注明出处!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 7:33:54

WandEnhancer技术深度解析:Electron应用增强框架的架构与实现原理

WandEnhancer技术深度解析&#xff1a;Electron应用增强框架的架构与实现原理 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer 在桌面应用生态系统中…

作者头像 李华
网站建设 2026/7/14 7:33:36

TMC7300与PIC18F47K42组合的直流电机驱动方案

1. TMC7300与PIC18F47K42组合的独特优势有刷直流电机&#xff08;BDC&#xff09;在工业控制、消费电子和自动化设备中广泛应用&#xff0c;但传统驱动方案常面临效率低、控制精度差和系统复杂等问题。TMC7300这款高度集成的电机驱动器芯片&#xff0c;配合PIC18F47K42微控制器…

作者头像 李华
网站建设 2026/7/14 7:32:26

美团LongCat-2.0:1.6万亿参数MoE大模型的完整指南

美团LongCat-2.0&#xff1a;1.6万亿参数MoE大模型的完整指南 【免费下载链接】LongCat-2.0 项目地址: https://ai.gitcode.com/meituan-longcat/LongCat-2.0 探索美团LongCat-2.0&#xff1a;一款拥有1.6万亿参数的混合专家模型&#xff0c;在AI领域掀起新的技术革命&…

作者头像 李华
网站建设 2026/7/14 7:31:41

mlx-community/Z-Image-bf16核心架构揭秘:S3-DiT与Qwen3-4B的完美融合

mlx-community/Z-Image-bf16核心架构揭秘&#xff1a;S3-DiT与Qwen3-4B的完美融合 【免费下载链接】Z-Image-bf16 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/Z-Image-bf16 想要在Apple Silicon上体验高性能的文本到图像生成吗&#xff1f;mlx-commun…

作者头像 李华