如何保证接口幂等性

如何保证接口幂等性

1、幂等性是什么?

接口幂等性是指用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了不同的结果。

2、使用幂等性的场景有哪些?
  1. 页面点击保存按钮时,不小心快速点了两次,表中竟然产生了两条重复的数据,只是id不一样。
  2. 我们在项目中为了解决接口超时问题,通常会引入了重试机制。第一次请求接口超时了,请求方没能及时获取返回结果(此时有可能已经成功了),为了避免返回错误的结果(这种情况不可能直接返回失败吧?),于是会对该请求重试几次,这样也会产生重复的数据。
  3. 消息重复消费,在使用消息中间件来处理消息队列,且手动 ack 确认消息被正常消费时。如果消费者突然断开连接,那么已经执行了一半的消息会重新放回队列。当消息被其他消费者重新消费时,如果没有幂等性,就会导致消息重复消费时结果异常,如数据库重复数据,数据库数据冲突,资源重复等。
3、如何保证接口幂等性?
  • 悲观锁
  • 乐观锁(版本号)
  • 唯一索引
  • 分布式锁
  • 去重表
  • token机制
4、详解具体实现
4.1、insert前先select(无法处理高并发)

​ 通常情况下,在保存数据的接口中,我们为了防止产生重复数据,一般会在insert前,先根据namecode字段select一下数据。如果该数据已存在,则执行update操作,如果不存在,才执行 insert操作。

该方案可能是我们平时在防止产生重复数据时,使用最多的方案。但是该方案不适用于并发场景,在并发场景中,要配合其他方案一起使用,否则同样会产生重复数据。

4.2、insert前先select并配合版本号,支持高并发(乐观锁)
  1. 先根据id查询用户信息,包含version字段

  2. 根据id和version字段值作为where条件的参数,更新用户信息,同时version+1

  3. 判断操作影响行数,如果影响1行,则说明是一次请求,可以做其他数据操作。

  4. 如果影响0行,说明是重复请求,则直接返回成功。

4.3、token机制

通过token 机制实现接口的幂等性,这是一种比较通用性的实现方法。

示意图如下:

具体流程步骤:

  1. 客户端会先发送一个请求去获取 token,服务端会生成一个全局唯一的 ID 作为 token 保存在 redis 中,同时把这个 ID 返回给客户端。

  2. 客户端第二次调用业务请求的时候必须携带这个 token。

  3. 服务端会校验这个 token,如果校验成功,则执行业务,并删除 redis 中的 token。

  4. 如果校验失败,说明 redis 中已经没有对应的 token,则表示重复操作,直接返回指定的结果给客户端

4.5、去重表

这种实现方式是利用 mysql 唯一索引的特性。示意图如下:

具体流程步骤:

  1. 建立一张去重表,其中某个字段需要建立唯一索引

  2. 客户端去请求服务端,服务端会将这次请求的一些信息插入这张去重表中

  3. 因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑

  4. 如果插入失败,则代表已经执行过当前请求,直接返回。

4.6、分布式锁

这种实现方式是基于 SETNX 命令实现的。

SETNX key value:将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。该命令在设置成功时返回 1,设置失败时返回 0。示意图如下:

具体流程步骤:

  1. 客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段

  2. 将该字段以 SETNX 的方式存入 redis 中,并根据业务设置相应的超时时间

  3. 如果设置成功,证明这是第一次请求,则执行后续的业务逻辑

  4. 如果设置失败,则代表已经执行过当前请求,直接返回

相关推荐
阿伟*rui1 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
Yaml45 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~5 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616885 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7895 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java6 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~6 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust