幂等性接口实现
1、什么是幂等性
幂等(idempotence),这个词源自数学,幂等性是数学中的一个概念,常见于抽象代数中。表达的是N次变换与1次变换的结果相同。简单来说,就是如果方法调用一次和调用多次产生的效果是相同的,它就具有幂等性。幂等函数或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数,这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
1.1 HTTP维度
HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的响应。
1.1.1 GET方法
HTTP GET方法用于获取资源,不应有副作用,所以是幂等的,具备幂等性。比如:GET https://www.wkcto.com/course/100方法不会改变资源的状态,不论调用1次还是N次都没有副作用。需要注意的是,这里强调的是一次和N次具有相同的副作用,而不是每次GET的结果相同。
1.1.2 DELETE方法
HTTP DELETE方法用于删除资源,有副作用,但它应该满足幂等,具备幂等性。比如:DELETE https://www.wkcto.com/article/detail/10,调用一次和N次对系统产生的副作用是相同的,即删除id为10的帖子,因此调用者可以多次调用或刷新页面而不必担心引起错误。
1.1.3 POST方法
HTTP POST所对应的URI为资源的接收者,不具备幂等性。比如:POST https://www.wkcto.com/article的语义是发表一篇文章,两次相同的POST请求会在服务器端创建两份相同的资源,所以POST方法不具备幂等性。
1.1.4 PUT方法
HTTP PUT所对应的URI是要创建或更新的资源,具备幂等性。比如PUT https://www.wkcto.com/article/5321的语义是创建或更新ID为5321的文章,对同一URI进行多次PUT和一次PUT的结果是相同的,因此PUT方法具备幂等性。
2、产生幂等性问题的场景
幂等性问题在分布式、微服务架构中随处可见:
- 因网络波动,可能会引起重复请求;
- 用户重复操作,在使用产品时可能会无意地触发多次下单多次交易,甚至没有响应而有意触发多笔交易;
- 应用使用了失败或超时重试机制(如Nginx重试、RPC重试或业务层重试等)
- 第三方平台的接口(如支付成功回调接口),因为异常导致多次异步回调;
- 中间件/应用服务根据自身特性,也有可能进行重试;
- 用户双击提交按钮;
- 页面重复刷新;
- 使用浏览器后退按钮重复之前的操作,导致重复提交表单;
3、幂等在哪一层实现
DAO
4、如何保证幂等性
4.1 前端实现(不可靠)
4.1.1 按钮只可操作一次
一般是提交后把按钮置灰或loading状态,可以使用一些js组件来实现,消除用户因为重复点击而产生的副作用,比如添加操作,由于点击两次而产生两条记录。
4.1.2 Token机制
进入页面时申请一个token,分别存储在session和表单隐藏域中,提交表单时,判断表单中的token与session中的token是否都存在且一致,如果存在且一致,说明是第一次提交,清除session里的token,继续操作,否则说明非正常操作。
4.1.3 使用Post/Redirect/Get模式
所谓Post/Redirect/Get(PRG)模式,就是在提交后执行页面重定向。简单来说,当用户提交了表单后,执行一个客户端的重定向,转到提交成功信息页面,这样即避免了用户刷新页面导致重复提交,也能消除按前进和后退导致的重复提交的问题。
缺点:
- 由于服务器响应缓慢,用户刷新提交POST请求造成的重复提交。
- 用户恶意避开客户端预防多次提交手段,进行重复数据提交。
4.2 后端实现
4.2.1 使用唯一索引防止新增脏数据
当数据重复时,插入数据库会抛出异常,以此来保证不会出现脏数据,这是一种简单粗暴的方法。
4.2.2 Token + Redis的幂等方案
分为两个阶段:申请token阶段和业务操作阶段。以支付为例:
- 第一阶段,在进入到提交订单页面之前,需要订单系统根据用户信息向支付系统发起一次申请token的请求,支付系统将token保存到redis缓存中,为第二阶段作准备;
- 第二阶段,订单系统拿着申请到的token发起支付请求,支付系统会检查redis中是否存在该token,如果存在,表示第一次发起的支付请求,开始支付逻辑处理,处理完逻辑后删除redis中token。
当重复请求的时候,检查到缓存中的token不存在,表示非法请求。
该方案的不足之处在于需要与系统交互两次。
4.2.3 状态机幂等
针对更新操作,比如业务上需要修改订单状态,订单有待支付、支付中、支付成功、支付失败、订单超时关闭等状态,在设计的时候最好只支持状态的单向改变(不可逆),这样在更新的时候where条件里可以加上status=期望的原来的status,多次调用的话实际上也只会执行一次。
4.2.4 乐观锁实现幂等
如果更新已有数据,可以进行加锁更新,也可以设计表结构时使用乐观锁,通过version做乐观锁,这样即能保证执行效率,又能保证幂等。乐观锁的version版本在更新业务数据时要自增。
以版本号为乐观锁:
- 查询数据,得到版本号,version = 1;
- 通过版本号更新,版本号匹配就更新,否则不能更新 UPDATE T_ACCOUNT SET MONEY = MONEY - #money#, VERSION = VERSION + 1 WHERE ID = #id# AND VERSION = 1。
也可以采用update with condition,更新带条件,实现乐观锁,通过version或者其他条件来实现乐观锁。
4.2.5 防重表实现幂等性
新建一张防重表(防止数据重复的表)。使用唯一主键做防重表的唯一索引,比如订单号orderNo,每次请求都根据订单号向防重表中插入一条数据,第一次请求查询订单支付状态,当然订单没有支付,进行支付操作,支付前先向防重表中插入该订单的订单号,插入成功说明可以支付,执行完更新订单状态。后续订单因为表中唯一索引而插入失败,直到第一次的请求操作完成,删除防重表中的数据。可以看出,防重表的作用就是加锁。
这种方案其实也是一种分布式锁的实现方式,与4.2.7的redis和zookeeper实现分布式锁相呼应。
4.2.6 SELECT + INSERT实现幂等性
简单来说,就是插入之前先查询,符合要求再插入。该方案在没有并发的系统中可以解决幂等问题,在单JVM有并发的时候可以通过JVM加锁来保证幂等性,在分布式环境下是无法使用的。
4.2.7 分布式锁实现幂等性
在进入方法时,先去获锁,如果获取到了,就继续后面的流程。如果没有,就等待锁的释放。当执行完方法后,释放锁,当然,锁要设个超时时间,防止意外没有释放到锁。它可以用来解决分布式系统的幂等性。
使用分布式锁类似于防重表,思路相同,都是同一时间只能完成一次支付请求。只是将防重并发放到了缓存中,较为高效。
常用的分布式锁的实现方案是redis和zookeeper等工具。
4.2.8 缓冲队列实现幂等性
将请求快速地接收下来,放入缓冲队列,后续使用异步任务处理队列中的数据,过滤掉重复的请求,此方案的优点是改同步为异步,提高吞量;缺点是不能及时地返回请求结果,需要后续轮询处理结果。
4.2.9 全局唯一号实现幂等性
比如通过source来源 + seq序列号来判断请求是否重复,在并发时只能处理一个请求,其它相同并发请求要么返回请求重复,要么等待前面请求执行完成再执行。
相关文章:
幂等性接口实现
1、什么是幂等性 幂等(idempotence),这个词源自数学,幂等性是数学中的一个概念,常见于抽象代数中。表达的是N次变换与1次变换的结果相同。简单来说,就是如果方法调用一次和调用多次产生的效果是相同的&…...
C++ 语言特性29 - 协程介绍
一:什么是协程 C20 引入了协程(coroutine),这是 C 标准库中一个强大的新特性。协程是一种可以在执行中暂停并随后恢复的函数,允许程序在异步或并行场景下高效管理任务,而不需要传统的线程或复杂的回调机制。…...
[Day 84] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
AI在公共安全中的應用實例 引言 隨著技術的進步,人工智能(AI)在公共安全領域的應用越來越廣泛。AI不僅能夠提高安全部門的工作效率,還能有效幫助預防和處理各類公共安全事件。從人臉識別、行為分析到災害預測,AI正在…...
八大排序--01冒泡排序
假设有一组数据 arr[]{2,0,3,4,5,7} 方法:开辟两个指针,指向如图,前后两两进行比较,大数据向后冒泡传递,小数据换到前面。 一次冒泡后,数组中最大…...
【Kubernetes】常见面试题汇总(五十)
目录 112.考虑一个公司要向具有各种环境的客户提供所有必需的分发产品的方案。您如何看待他们如何动态地实现这一关键目标? 113.假设一家公司希望在从裸机到公共云的不同云基础架构上运行各种工作负载。在存在不同接口的情况下,公司将如何实现这一目标&…...
Linux 操作系统中的 main 函数参数和环境变量
在聊进程替换之前,有一些基础知识我们得先弄清楚。掌握了这些内容,不仅能让你更轻松地理解 Shell 是如何工作的,还能为之后的进程替换操作铺好路。进程替换说白了就是 Shell 的基本原理,它能把一个命令的输出直接当成另一个命令的…...
Vue项目中通过插件pxtorem实现大屏响应式
一、原理 rem单位代表的是根节点的font-size大小,所以当我们在页面上使用rem去替代px的时候,就可以通过修改根节点font-size的值,动态地让页面上的元素根据不同浏览器宽高下去实现变化。 二、工具 1.postcss-pxtorem 作用:在编…...
(Django)初步使用
前言 Django 是一个功能强大、架构良好、安全可靠的 Python Web 框架,适用于各种规模的项目开发。它的高效开发、数据库支持、安全性、良好的架构设计以及活跃的社区和丰富的文档,使得它成为众多开发者的首选框架。 目录 安装 应用场景 良好的架构设计…...
【星汇极客】单片机竞赛之2024睿抗机器人大赛-火线速递赛道(持续更新)
前言 本人是一名嵌入式学习者,在大学期间也参加了不少的竞赛并获奖,包括但不限于:江苏省电子设计竞赛省一、睿抗机器人国二、中国高校智能机器人国二、嵌入式设计竞赛国三、光电设计竞赛国三、节能减排竞赛国三。 后面会经常写一下博客&…...
生信科研,教授(优青)团队一站式指导:高通量测序技术--农业植物基因组分析、组蛋白甲基化修饰、DNA亲和纯化测序、赖氨酸甲基化
组蛋白甲基化修饰工具(H3K4me3 ChIP-seq) 组蛋白甲基化类型也有很多种,包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守,是被研究最多的组蛋白修饰之一。 DNA亲和纯化测序 DNA亲…...
【Immich部署与访问】自托管媒体文件备份服务 Immich 本地化部署与远程访问存储数据
文章目录 前言1.关于Immich2.安装Docker3.本地部署Immich4.Immich体验5.安装cpolar内网穿透6.创建远程链接公网地址7.使用固定公网地址远程访问 前言 本篇文章介绍如何在本地搭建lmmich图片管理软件,并结合cpolar内网穿透实现公网远程访问到局域网内的lmmich&#…...
AI少女/HS2甜心选择2 仿逆水寒人物卡全合集打包
内含AI少女/甜心选择2 仿逆水寒角色卡全合集打包共6张 内含:白灵雪魅落霞飞雁君临华歌白君临华歌黑平野星罗晚香幽韵 下载地址: https://www.51888w.com/436.html 部分演示图:...
C/C++逆向:数据类型识别
在逆向工程中,数据类型识别是理解程序逻辑的重要步骤,因为它直接影响对程序逻辑和功能的理解,识别出数据类型有助于确定变量的含义和函数的行为。在分析恶意软件或者寻找安全漏洞时,识别数据类型能够帮助发现代码中的潜在问题。例…...
PASCAL VOC 2012数据集 20类物体,这些物体包括人、动物(如猫、狗、鸟等)、交通工具(如车、船、飞机等)以及家具(如椅子、桌子、沙发等)。
VOC2012数据集是PASCAL VOC挑战赛官方使用的数据集之一,主要包含20类物体,这些物体包括人、动物(如猫、狗、鸟等)、交通工具(如车、船、飞机等)以及家具(如椅子、桌子、沙发等)。每个…...
题目:最左边的数字
问题 - 1060 (hdu.edu.cn) 解题思路: 数字很大,使用科学计数法。则,我们需要的是a的整数位,最终求出a即可。 取对数:nlgnmlga,移项:lganlgn-m,接下来我们需要求m。 …...
第 4 章 Spring IoC容器之BeanFactory
Spring 的 IoC 容器是一个提供 IoC 支持的轻量级容器,除了基本的 IoC 支持,它作为轻量级容器还提供了 IoC 之外的支持。 Spring 提供了两种容器类型:BeanFactory 和 ApplicationContext: BeanFactory,基础类型 IoC 容…...
滚雪球学Oracle[2.3讲]:Oracle Listener配置与管理
全文目录: 前言一、Oracle Listener的基础概念1.1 什么是Oracle Listener?Listener的作用: 1.2 Oracle Listener的配置文件示例listener.ora配置文件: 1.3 启动与管理Listener 二、多Listener配置与负载分担2.1 多Listener的应用场…...
免费送源码:Javaspringboot++MySQL springboot 社区互助服务管理系统小程序 计算机毕业设计原创定制
摘 要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受居民的喜爱,社区互助服务管理系统小程序被居民普遍使用,为…...
成都睿明智科技有限公司抖音电商新蓝海的领航者
在当今这个数字化浪潮汹涌的时代,电商行业正以惊人的速度迭代升级,而抖音电商作为新兴势力,更是凭借其庞大的用户基数、精准的算法推荐和高度互动的社区氛围,成为了众多商家竞相追逐的蓝海市场。在这片充满机遇与挑战的海洋中&…...
不可错过!CMU最新《生成式人工智能大模型》课程:从文本、图像到多模态大模型
1. 课程简介 从生成图像和文本到生成音乐和艺术,生成模型一直是人工智能的关键挑战之一。本课程将探讨推动生成模型和基础模型(Foundation Models)最近进展的机器学习和人工智能技术。学生将学习、开发并应用最先进的算法,使机器…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
