如何保证接口的幂等性

什么是幂等性

一个接口被重复调用,对系统的影响是一致的。无论是一次还是多次,数据是一致的,效果也一样。

什么情况下需要幂等

SELECT col1 FROM tab1 WHER col2=2,无论执行多少次都不会改变状态,是天然的幂等。
UPDATE tab1 SET col1=1 WHERE col2=2,无论执行成功多少次状态都是一致的,因此也是幂等操作。
UPDATE tab1 SET col1=col1+1 WHERE col2=2,每次执行的结果都会发生变化,这种不是幂等的。
insert into user(userid,name) values(1,‘a’) 如userid为唯一主键,即重复操作上面的业务,只会插入一条用户数据,具备幂等性。
如userid不是主键,可以重复,那上面业务多次操作,数据都会新增多条,不具备幂等性。
delete from user where userid=1,多次操作,结果一样,具备幂等性

如何保证幂等

唯一主键

利用数据库主键唯一的特性,解决在执行insert语句时的幂等性问题。(在分库分表情况下无效)

去重表

适用于有唯一标识的插入场景,新建一张去重表,添加唯一索引,当执行插入操作时,将唯一标识保存到去重表唯一索引字段,当重复请求时,因为有唯一约束,导致数据库抛异常回滚。

乐观锁机制

适用于更新场景,update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
乐观锁只是在更新数据那一刻锁表,其他时间不锁表

状态机控制

这种方法适合在有状态机流转的情况下,比如就会订单的创建和付款,订单的付款肯定是在之前,这时我们可以通过在设计状态字段时,使用int类型,并且通过值类型的大小来做幂等,比如订单的创建为0,付款成功为100。付款失败为99

对外提供接口的api如何保证幂等

对外提供接口为了支持幂等调用,接口有两个字段必须传,一个是来源source,一个是来源方序列号seq,这个两个字段在提供方系统里面做联合唯一索引,这样当第三方调用时,先在本方系统里面查询一下,是否已经处理过,返回相应处理结果;没有处理过,进行相应处理,返回结果。

在Spring Cloud项目中,保证接口幂等性是非常重要的,尤其是在微服务架构下。下面将介绍几种常见的策略和技术手段来确保接口幂等性。 ### 1. **使用全局唯一ID(UUID)** 每条请求都应带上一个全球唯一的标识符(UUID),以此作为去重的关键依据。我们可以在过滤器或拦截器处对该UUID进行校验,避免重复处理相同的请求。 #### 实现步骤: - 客户端生成并传递`requestId` - 服务器接收到请求后将其存入Redis或其他缓存工具里 - 当再次接到相同`requestId`时,直接返回之前的响应结果 ```java public class IdempotentFilter extends OncePerRequestFilter { @Autowired private RedisTemplate<String, String> redisTemplate; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 获取 requestId 参数值 String requestId = request.getParameter("idempotencyKey"); if (redisTemplate.opsForValue().get(requestId) != null) { // 已经有该键表示已经执行过了 直接结束掉本次调用 return; } try { // 执行正常链路逻辑... filterChain.doFilter(request, response); // 设置到缓存中防止下次再进入业务层逻辑里面去了 防止并发场景导致的问题 redisTemplate.opsForValue().set(requestId, "executed", Duration.ofMinutes(5)); } catch (Exception e){ throw new RuntimeException(e.getMessage()); } } } ``` ### 2. **乐观锁机制** 对于一些涉及数据变更的操作,我们可以利用数据库表中的版本号字段(`version`)来进行判断。当发生更新操作时,除了指定要修改的数据外还要附加当前记录对应的版本信息。SQL语句会添加额外条件限制只能作用于特定版本的数据行上;如果实际影响行数不符合预期说明其他地方抢先一步进行了改动那么此时应当告知用户尝试刷新页面获取最新的状态后再试一次即可。 ```sql UPDATE orders SET status='PAID', version=version+1 WHERE order_id=? AND version=? ``` **注:** `order_id` 和 `version` 分别对应订单编号及版本计数。 ### 3. **基于消息队列的幂等消费** 考虑到异步任务的存在情况,如RabbitMQ/Kafka这类的消息中间件可能会因为网络抖动等原因造成消费者重复接收同一条消息的情形。因此我们需要在消费方建立一套针对主题/分区偏移量映射关系的记忆库,从而杜绝此类现象的发生几率。 --- 以上就是在Spring Cloud环境下常用的几种保证接口幂等性的做法。当然根据具体的业务需求还可以有更多的解决方案可供选择。总之核心思想就是尽量减少不必要的资源竞争以及引入合适的协调组件共同协作达成目标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fisher3652

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值