面试官:如何保证接口幂等性?一口气说了9种方法!

本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~

Github地址


大家好,我是大彬~

今天来聊聊接口幂等性。

什么是接口幂等性?如何保证接口幂等性?

什么是接口幂等性?

首先看看幂等性的概念:

幂等性原本是数学上的概念,用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。

比如下面这些情况,如果没有实现接口幂等性会有很严重的后果:支付接口,重复支付会导致多次扣钱 ;订单接口,同一个订单可能会多次创建。

为什么会产生接口幂等性问题?

那么,什么情况下,会产生接口幂等性的问题呢?

  • 网络波动, 可能会引起重复请求
  • 用户重复操作,用户在操作时候可能会无意触发多次下单交易,甚至没有响应而有意触发多次交易应用
  • 使用了失效或超时重试机制(Nginx重试、RPC重试或业务层重试等)
  • 页面重复刷新
  • 使用浏览器后退按钮重复之前的操作,导致重复提交表单
  • 使用浏览器历史记录重复提交表单
  • 浏览器重复的HTTP请求
  • 定时任务重复执行
  • 用户双击提交按钮

面试网站

如何保证接口幂等性?

那么最关键的来了,如何保证接口幂等性?

解决办法分为两个方向,一个方向是客户端防止重复调用,一个是服务端进行校验。当然,客户端防止重复提交并不是绝对可靠的,优点是实现起来比较简单。

按钮只可操作一次

一般是提交后把按钮置灰或loding状态,消除用户因为重复点击而产生的重复记录,比如添加操作,由于点击两次而产生两条记录。

token机制

功能上允许重复提交,但要保证重复提交不产生副作用,比如点击n次只产生一条记录,具体实现就是进入页面时申请一个token,然后后面所有的请求都带上这个token,后端根据token来避免重复请求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y4egwIRj-1679818606246)(http://img.topjavaer.cn/img/接口幂等.png)]

使用唯一索引防止新增脏数据

利用数据库唯一索引机制,当数据重复时,插入数据库会抛出异常,保证不会出现脏数据。

乐观锁

如果更新已有数据,可以进行加锁更新,也可以设计表结构时使用乐观锁,通过version来做乐观锁,这样既能保证执行效率,又能保证幂等, 乐观锁的version版本在更新业务数据要自增。

update table set version = version + 1 where id = #{id} and version = #{version}

示例: 当有重复请求的时候,第一个请求会获取当前商品的version版本号,得到的version为1,紧接着由于第一个请求还没更新商品的version,第二个请求获取的version依然也是1, 这时候第一个请求操作更新的时候带上version并作为条件并且自增更新,这时候商品的version就会变成2,当第二个请求去操作更新的时候明显version不一致导致更新失败。

select + insert or update or delete

该方案就是操作之前先查询一下,符合要求再插入,该方案在没有并发的系统中可以解决幂等问题,在单JVM有并发的时候可以用JVM加锁来保证幂等性,在分布式环境它是无法保证幂等性,可以使用分布式来保证。

分布式锁

如果是分布式系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)。

状态机幂等

在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助 。

防重表

以支付为例: 使用唯一主键去做防重表的唯一索引,比如使用订单号作为防重表的唯一索引,每一次请求都根据订单号向防重表中插入一条数据,插入成功说明可以处理后面的业务,当处理完业务逻辑之后删除防重表中的订单号数据,后续如果有重复请求,则会因为防重表唯一索引原因导致插入失败,直接返回操作失败,直到第一次请求返回结果,可以看出防重表作用就是加锁的功能。

注: 最好结合状态机幂等先判断一下

缓冲队列

将请求都快速地接收下来后放入缓冲队列中,后续使用异步任务处理队列中的数据,过滤掉重复的请求,该解决方案优点是同步处理改成异步处理、高吞吐量,缺点则是不能及时地返回请求结果,需要后续轮询得处理结果。


最后给大家分享一个Github仓库,上面有大彬整理的300多本经典的计算机书籍PDF,包括C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,可以star一下,下次找书直接在上面搜索,仓库持续更新中~

Github地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/3768.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

idea 关于git使用总结分享

文章目录前言idea 关于git使用总结分享1. git 目录指定自己的git2. git 回滚到指定提交3. git 回滚某个文件4. 从远程仓库分支拉取最新代码5. 切换分支6. 上传到远程仓库7. git 关联上游服务8. 从上游分支拉取最新的代码9. 从上游仓库上取一个新的branch到远程仓库前言 如果您觉…

【LeetCode】二叉树的后序遍历(递归,迭代)

目录 题目要求:给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 方法一:递归 方法二:迭代 思路分析: 代码展示: 复杂度分析 方法三:迭代进阶 思路分析: 代码展示&a…

python玄阶斗技--tkinter库

目录 一.tkinter库介绍 二.功能实现 1.窗口创建 2.Button 按钮 3.Entry 文本输入域 4.text 文本框 5.Listbox 多选下拉框 6.Radiobutton 多选项按钮 7.Checkbutton 多选按钮 8.Scale 滑块(拉动条) 9.Scroolbar 滚动条 10.Menu 菜单栏 11. messagebox 消息框 12…

比肩ChatGPT的国产AI:文心一言——有话说

🔗 运行环境:chatGPT,文心一言 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 #### 防伪水印——左手の明天 #### 💗 大家好&am…

剑指offer-二维数组中的查找

文章目录题目描述题解一 无脑暴力循环题解二 初始二分法🌕博客x主页:己不由心王道长🌕! 🌎文章说明:剑指offer-二维数组中的查找🌎 ✅系列专栏:剑指offer 🌴本篇内容:对剑…

怎么设计一个秒杀系统

1、系统部署 秒杀系统部署要单独区别开其他系统单独部署,这个系统的流量肯定很大,单独部署。数据库也要单独用一个部署的数据库或者集群,防止高并发导致整个网站不可用。 2、防止超卖 100个库存,1000个人买,要保证不…

脉诊(切脉、诊脉、按脉、持脉)之法——入门篇

认识脉诊何谓脉诊?脉诊的渊源脉诊重要吗?脉诊确有其事,还是故弄玄虚?中医科学吗?如何脉诊?寸口脉诊法何谓脉诊? 所谓脉诊,就是通过把脉来诊断身体健康状况的一种必要手段。 …

ShowMeAI周刊 | AI独立开发者:帆船旅行但月入万刀;创业吧!新黄金时代来了;资本看好哪些创业方向;被AI震麻的一周again

这是ShowMeAI周刊的第8期。聚焦AI领域本周热点,及其在各圈层泛起的涟漪;拆解AI独立开发者的盈利案例,关注中美AIGC的创业者们,并提供我们的商业洞察。欢迎关注与订阅! | 👀日报&周刊合辑 ⌛ 『Danielle…

vue3 解决各场景 loading过度 ,避免白屏尴尬!

Ⅰ、前言 当我们每次打卡页面,切换路由,甚至于异步组件,都会有一个等待的时间 ;为了不白屏,提高用户体验,添加一个 loading 过度动画是 非常 常见的 ;那么这几种场景我们应该把 loading 加在哪…

JavaEE多线程-线程池

目录线程池Java标准库提供的线程池线程池的实现线程池 线程池和和字符串常量池, 数据库连接池一样, 都是为了提高程序的运行效率, 减少开销。 随着并发程度的提高, 当我们去频繁的创建和销毁线程, 此时程序的开销还是挺大的, 为了进一步提高效率, 就引入了线程池, 程序中所创建…

基于Java+SSM+Vue的旅游资源网站设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍:专注于Java技术领域和毕业项目实战 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 Java项目精品实战案例(200套) 目录 一、效果演示 二、…

Java语言-----封装、继承、抽象、多态、接口

目录 前言 一.封装 1.1封装的定义 1.2访问修饰符的使用 二.继承 2.1继承的定义 2.2继承的方法 2.3继承使用注意点 三.多态 3,1多态的定义 3.2动态绑定 3.3方法重写 3.4向上(向下)转型 四.抽象 4.1抽象的概述和定义 4.2抽象的使用 五…

python例程:AI智能联系人管理的程序

目录《AI智能联系人管理》程序使用说明主要代码演示代码工程下载路径《AI智能联系人管理》程序使用说明 在PyCharm中运行《AI智能联系人管理》即可进入如图1所示的系统主界面。 图1 系统主界面 说明:在运行程序前,先将当前的计算机连接互联网&#xff…

【网络】https协议

🥁作者: 华丞臧. 📕​​​​专栏:【网络】 各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞收藏关注)。如果有错误的地方,欢迎在评论区指出。 推荐一款刷题网站 👉 LeetCode刷题网站 文章…

【深度学习】常见的梯度下降的方法

批量梯度下降(Batch Gradient Descent,BGD) 这个方法是当所有的数据都经过了计算之后再整体除以它,即把所有样本的误差做平均。这里我想提醒你,在实际的开发中,往往有百万甚至千万数量级的样本&#xff0c…

python基于django的校园拼车系统

开发语言:Python 框架:django Python版本:python3 数据库:mysql 数据库工具:Navicat 登录注册模块 1.管理员登录 2.普通用户注册登录,注册时要求密码必须用数字、字母、特殊字符起码两种,并且…

Python每日一练(20230327)

目录 1. 最大矩形 🌟🌟🌟 2. 反转链表 II 🌟🌟 3. 单词接龙 II 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日…

C生万物 | 校招热门考点 —— 结构体内存对齐

文章目录一、前言结构体偏移量计算:offsetof二、规则介绍例题的分解与细说三、习题演练1、练习①2、练习②四、为什么存在内存对齐?1、平台原因(移植原因)2、性能原因五、如何修改默认对齐数六、实战演练✍一道百度笔试题: offsetof 宏的实现&#x1f4…

自己设计的网站,如何实现分页功能?(详细代码+注释)

目录 前言 实现分页功能 需求分析 客户端开发 服务器开发 前后端交互——两种前端得到 文章总页数 的方法,那种更合适? 前言 你在设计网站的时候是否有过这样的烦恼:“我设计的网站怎么就是从上到下一条线内容全部展开,一点都…

IDEA 热部署,修改代码不用重启项目

热部署指在修改项目代码的时候不重启服务器让修改生效。安装JRebel and XRebelFile->Settings,然后Plugins-> Marketplace,输入JRebel,安装如下插件——JRebel and XRebel ,重启idea激活JRebel and XRebel第一行输入网址&am…