当前位置: 首页 > news >正文

01-幂等性解释,问题及常用解决方案

目录

1. 幂等性简介

2.  后端如何解决幂等性问题

2.1 数据库层面

-> 2.1.1 防重表 

-> 2.1.2 数据库悲观锁(不建议,容易出现死锁情况) 

-> 2.1.3 数据库乐观锁 

-> 2.1.4 乐观锁CAS算法原理

2.2 锁层面

2.3 幂等性token层面

-> 2.3.1 简介文字描述: 

-> 2.3.2 简介图示:  

​编辑

-> 2.3.3 创建注解

-> 2.3.4  创建请求拦截器

----->方案一: 使用incr保证原子性

----->方案一代码: 拦截器

====>方案二: 使用分布式锁, 这篇文章暂不介绍

-> 2.3.5 获取幂等token代码

-> 2.3.6 接口测试

-> 2.3.7 使用测试工具进行测试

 -> 2.3.8 幂等校验token的优,缺点

-----> 2.3.8.1 使用的优点: 

-----> 2.3.8.2 使用的缺点: 

3. 前端如何操作来避免幂等问题 

-> 3.1前端防重

-> 3.2 PRG模式


1. 幂等性简介

分布式或微服务思想实现系统架构设计中, 服务相互调用,可能存在服务调用延迟或失败情况。服务端可能会进行多次点击提交。如果这样请求多次的话,那最终处理的数据结果就一定要保证统一,如 订单创建,支付扣款,库存扣减,物流发货等。此时就需要通过保证业务幂等性方案来完成。

2.  后端如何解决幂等性问题

2.1 数据库层面

-> 2.1.1 防重表 

创建唯一索引: 多用于详情信息, 个人账户等业务,如果并发情况下出现多条,数据库报异常

 创建唯一组合索引: 可以创建组合索引来保证唯一性

-> 2.1.2 数据库悲观锁(不建议,容易出现死锁情况) 

加入悲观锁, for update, 有主键索引/明确索引就是行锁, 不然就是表锁

文章介绍跳转: -> mysql for update 详细介绍

-> 2.1.3 数据库乐观锁 

占用数据库资源, 需要有版本号, 先查询版本号作为老的版本(oldVersion)存起来, 进行修改操作, 然后把这个值也进行修改+1 条件是version= oldVersion, 如果version不正确 修改失败

version= 5  100个线程同时取到5  其中一个修改成功version=6, 则其他99个失败

-> 2.1.4 乐观锁CAS算法原理

简介: compare and swap:比较与交换 , 核心即为 冲突检测和数据更新

文章介绍跳转: ->

2.2 锁层面

锁系列文章跳转(待定) -> 

2.3 幂等性token层面

-> 2.3.1 简介文字描述: 

        1. 先制作幂等性token生成器, 创建token

        2. 创建注解, 写入默认值 表示是否开启校验

        3. 写拦截器 判断接口上是否有注解 如果没有,放行

        4. 有注解的, 判断请求头中是否存在幂等token, 不存在 拦截请求

        5. 存在, 判断幂等token真实性(是否过期), 不存在或incr数值异常 删除幂等token   拦截请求

        6. 一切正常,删除token,放行请求, 进入controller

-> 2.3.2 简介图示:  

-> 2.3.3 创建注解

package *;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 幂等性校验* 需要多线程测试后* 查出是否需要优化* @author pzy* @version 0.1.1 测试版本*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotentAnn {boolean value() default true;
}

-> 2.3.4  创建请求拦截器

----->方案一: 使用incr保证原子性

简介: Redis 的 INCR 命令可以将存储在指定键中的数字值增加 1。INCR 命令是一个原子性操作, 意味着它在执行过程中不会被中断。 例如,假设您有一个名为 "counter" 的键,存储的值为 0。如果您使用 INCR 命令将其 增加 1,那么这个键的值就会变为 1。如果再次使用 INCR 命令将其增加 1,那么这个键的值 就会变为 2。 由于INCR 命令是原子性的,因此可以在并发环境下使用

----->方案一代码: 拦截器

package *;import *;
import *;
import *;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;import static com.aisce.common.constant.RedisKeyConstants.IDEMPOTENT_TOKEN;/*** 幂等性校验拦截器(用哪个工程粘过去即可)* 使用方式:* <p>* <p>* 后端操作: @ApiIdempotentAnn注解 添加到接口位置即可 其他无需操作* <p>* 前端操作: 在请求头中添加  idempotent参数* 示例: "idempotent": "fcc8b373-b867-4d6c-9915-e3bd668db7b6"** @author pzy* @version 0.1.1 初期版本*/
@Slf4j
@Component
@Order(2)
public class ApiIdempotentInterceptor extends HandlerInterceptorAdapter {@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 前置拦截器* 在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行,* 也就是说我们想调用的方法 不会被执行,但是你可以修改response为你想要的响应。*/@SuppressWarnings(value = {"all"})@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("===> 执行链2 执行");//如果handler不是和HandlerMethod类型,则返回trueif (!(handler instanceof HandlerMethod)) {return true;}//转化类型final HandlerMethod handlerMethod = (HandlerMethod) handler;//获取方法类final Method method = handlerMethod.getMethod();// 判断当前method中是否有这个注解boolean methodAnn = method.isAnnotationPresent(ApiIdempotentAnn.class);//如果有幂等性注解if (methodAnn && method.getAnnotation(ApiIdempotentAnn.class).value()) {// 需要实现接口幂等性//检查token//1.获取请求的接口方法boolean result = checkToken(request);//如果token有值,说明是第一次调用if (result) {//则放行return super.preHandle(request, response, handler);} else {//如果token没有值,则表示不是第一次调用,是重复调用response.setContentType("application/json; charset=utf-8");PrintWriter writer = response.getWriter();writer.print(new ObjectMapper().writeValueAsString(ResultResponse.error("重复调用,已拦截!")));writer.close();response.flushBuffer();log.error(String.format("===> %s 重复调用%s,已拦截!", request.getRemoteAddr(), request.getRequestURI()));return false;}}//否则没有该自定义幂等性注解,则放行return super.preHandle(request, response, handler);}/*** 幂等token的校验方法*/private boolean checkToken(HttpServletRequest request) {//从请求头对象中获取 幂等性校验token<idempotent>String idempotentToken = request.getHeader("idempotent");//如果不存在,则返回false,说明是重复调用if (StringUtils.isBlank(idempotentToken)) {return false;}//格式化幂等校验tokenidempotentToken = String.format(IDEMPOTENT_TOKEN, idempotentToken);if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(idempotentToken))) {return false;}//保证原子性<方式一>  incrLong num = stringRedisTemplate.opsForValue().increment(idempotentToken);if (num != null && num.intValue() != 2) {//只要逻辑不对 删除key, 阻止请求delIdempotentToken(idempotentToken);return Boolean.FALSE;}//否则就是存在,存在则把redis里删除token//return Boolean.TRUE;return delIdempotentToken(idempotentToken);}/*** 删除幂等校验token** @param idempotentToken* @return*/private Boolean delIdempotentToken(String idempotentToken) {return Boolean.TRUE.equals(stringRedisTemplate.delete(idempotentToken));}}

====>方案二: 使用分布式锁, 这篇文章暂不介绍

下篇文章预告: 分布式锁基本使用方式,以及配合注解实现快速加锁

-> 2.3.5 获取幂等token代码

  /*** 前端获取token,然后把该token放入请求的header中** @return*/@ApiOperation("获取幂等token")@GetMapping("/getIdempotentToken")public ResultResponse getIdempotentToken() {log.info("===> 获取幂等token <===");String idempotent = UUID.randomUUID().toString();stringRedisTemplate.opsForValue().set(String.format(IDEMPOTENT_TOKEN,idempotent),"1", Duration.ofSeconds(60*2));//2分钟 不随机数了 两分钟幂等失效拦截return ResultResponse.ok().setData(idempotent);}

-> 2.3.6 接口测试

ps:  使用方式: AxPost可以换成任意实体类

ResultResponse  随便的一个统一返回类型,没有写String 类型即可

    @ApiIdempotentAnn@PostMapping("/testCheck")public ResultResponse testCheck(@RequestBody AxPost axPosts) {log.info("======>专业测试幂等性接口 <=======");System.out.println(axPosts);return ResultResponse.ok("ok");}

-> 2.3.7 使用测试工具进行测试

测试工具介绍: Postman,ApiPost, Idea httpclient tools,ApiFox后端测试方式 

 -> 2.3.8 幂等校验token的优,缺点

-----> 2.3.8.1 使用的优点: 

        通过token机制来保证幂等是常见的解决方案,同时也适合绝大部分场景,使用方便,

业务执行出现异常时,客户端需重新获取令牌并发起访问即可。推荐使用先删除token方案。

-----> 2.3.8.2 使用的缺点: 

        每次的业务请求, 都会产生一个额外的请求去获取token,但出现失败次数一般不会很多, 算是一种资源的浪费,虽然redis性能很好.

3. 前端如何操作来避免幂等问题 

-> 3.1前端防重

通过前端防重保证幂等是最简单的实现方式,JS代码即可完成设置。可靠性并不好,可以通过工具跳过页面仍能重复提交。主要适用于表单重复提交或按钮重复点击。 

-> 3.2 PRG模式

PRG模式即POST-REDIRECT-GET。当用户进行表单提交时,会重定向到另外一个提交成功页面,而不是停留在原先的表单页面。这样就避免了用户刷新导致重复提交。防止通过浏览器按钮前进/后退导致表单重复提交。 

相关文章:

01-幂等性解释,问题及常用解决方案

目录 1. 幂等性简介 2. 后端如何解决幂等性问题 2.1 数据库层面 -> 2.1.1 防重表 -> 2.1.2 数据库悲观锁(不建议,容易出现死锁情况) -> 2.1.3 数据库乐观锁 -> 2.1.4 乐观锁CAS算法原理 2.2 锁层面 2.3 幂等性token层面 -> 2.3.1 简介文字描述: …...

SpringBoot配置文件

配置文件有两种格式&#xff1a; .properties .yml .properties是老版配置文件&#xff0c;.yml是新版配置文件 一、properties详解 IDEA社区版不支持 properties格式的日志的提示&#xff0c;需要安装相应插件。 3.1properties 基本语法 &#xff08;ps:小技巧&#xff0…...

基于蜣螂算法改进的DELM分类-附代码

蜣螂算法改进的深度极限学习机DELM的分类 文章目录蜣螂算法改进的深度极限学习机DELM的分类1.ELM原理2.深度极限学习机&#xff08;DELM&#xff09;原理3.蜣螂算法4.蜣螂算法改进DELM5.实验结果6.参考文献7.Matlab代码1.ELM原理 ELM基础原理请参考&#xff1a;https://blog.c…...

FPGA纯verilog代码实现图像对数变换,提供工程源码和技术支持

目录1、图像对数变换理论2、log系数的matlab生成3、FPGA实现图像对数变换4、vivado与matlab联合仿真5、vivado工程介绍6、上板调试验证并演示7、福利&#xff1a;工程代码的获取1、图像对数变换理论 对数变换可以将图像的低灰度值部分扩展&#xff0c;显示出低灰度部分更多的细…...

【Python百日进阶-Web开发-Vue3】Day516 - Vue+ts后台项目3:首页

文章目录 一、首页头部1.1 element-plus中找到适合的Container布局容器1.2 头部容器Layout 布局1.3 src/views/HomeView.vue二、侧边菜单栏2.1 element-plus中找到适合的Menu侧栏2.2 src/views/HomeView.vue三、侧边栏的动态路由3.1 src/views/HomeView.vue3.2 src/views/Goods…...

分析了 200 个 DeFi 项目,我发现了这些规律

作者&#xff1a;Ren & Heinrich翻译&#xff1a;dongdong在这篇文章中&#xff0c;我分享了我通过分析当前排名前 200 的 DeFi 加密项目的见解。这不是一项学术研究。尽管如此&#xff0c;这些发现对加密货币投资者来说具有附加值。我使用 https://defillama.com/ 的公共数…...

你领证了吗?各地2022下半年软考纸质证书发放中

不少同学都在关注2022下半年软考证书领取时间&#xff0c;截止至目前&#xff0c;江苏、南京、山东、浙江、贵州、云南、大连、广西地区的纸质证书可以领取了&#xff0c;请大家在证书申领时间内及时预约证书邮寄发放哦~ 江苏 证书领取时间&#xff1a;2023年2月3日起 南京 …...

将群晖NAS变为本地盘

本文介绍一个工具&#xff0c;可以在 Windows 系统下将群晖NAS的目录变为本地盘&#xff0c;好处是在外部访问的时候&#xff0c;能够大大改善体验。可以用本地的应用程序直接打开&#xff0c;速度依赖网络带宽&#xff0c;正常情况下&#xff0c;看视频是没有问题的。当然&…...

以太坊上交易异常Pending的处理方法

交易Pending ETH交易pending的原因: 1.交易GasPrice设置过低,共识节点不打包 2.账户Nonce不连续,一直处于交易池队列当中 只要确认了是哪种原因引起的,就可以做出对应的解决方案。 GasPrice设置过低 由于ETH共识节点是按照Gas价格从高到低打包交易,如果每笔交易的GasPr…...

第三节 第一个内核模块

hellomodule 实验 实验说明 硬件介绍 本节实验使用到STM32MP157 开发板 实验代码讲解 本章的示例代码目录为&#xff1a;linux_driver/module/hellomodule 从前面我们已经知道了内核模块的工作原理&#xff0c;这一小节就开始写代码了&#xff0c;跟hello world 一样&…...

从CNN到Transformer:基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。随着小卫星星座的普及&#xff0c;对地观测已具备多次以上的全球覆盖…...

操作系统的奋斗(三)内存管理

第三章 内存管理3.1内存管理概念3.1.1 内存管理的基本原理和要求&#xff08;1&#xff09;内存管理的主要功能3.1.2 覆盖和交换&#xff08;1&#xff09;覆盖&#xff08;2&#xff09;交换3.1.3 连续分配管理方式&#xff08;1&#xff09;单一连续分配&#xff08;2&#x…...

多选多的一种通用处理逻辑

开发的时候&#xff0c;我们经常会涉及元素的多选多&#xff0c;并且还需要对选中的元素进行拖动排序 通用的设计方案如下 游戏资源集合与游戏资源的绑定关系处理&#xff08;多选多的一种通用处理逻辑&#xff09; 可能的情况&#xff1a; 1.之前被选中的资源&#xff0c;现…...

Redis 的安装 + SpringBoot 集成 Redis

1.安装 Redis此处的 Redis 安装是针对 Linux 版本的安装, 因为 Redis 官方没有提供 Windows 版本, 只提供了 Linux 版本. 但是我们可以通过Windows 去远程连接 Redis.1.1 使用 yum 安装 Redis使用如下命令, 将 Redis 安装到 Linux 服务器:yum -y install redis1.2 启动 Redis使…...

为什么在容器中 1 号进程挂不上 arthas?

作者&#xff1a;卜比 本文是《容器中的 Java》系列文章之 4/n &#xff0c;欢迎关注后续连载 &#x1f603; 。 系列1&#xff1a;JVM 如何获取当前容器的资源限制&#xff1f; 系列2&#xff1a;Java Agent 踩坑之 appendToSystemClassLoaderSearch 问题 系列3&#xff1a;让…...

23种设计模式之策略模式

一、概念 就是将一系列算法封装起来&#xff0c;并使它们之间相互替换。被封装起来的算法具有独立性外部不可改变其特性。 策略模式属于对象行为模式&#xff0c;它通过对算法进行封装&#xff0c;把使用算法的责任和算法的实现分割开来&#xff0c;并委派给不同的对象对这些算…...

不会做UI自动化测试?一起设计框架再实践吧

目的相信做过测试的同学都听说过自动化测试&#xff0c;而UI自动化无论何时对测试来说都是比较吸引人的存在。相较于接口自动化来说它可以最大程度的模拟真实用户的日常操作与特定业务场景的模拟&#xff0c;那么存在即合理&#xff0c;自动化UI测试自然也是广大测试同学职业道…...

数据分析实战项目3:RFM用户分群

目录1、RFM模型介绍2、Excel实际RFM划分案例3、RFM案例3.1 数据加载和基本信息查看3.2 数据预处理和RFM的初始值计算3.3 RFM区间和划分和分值计算3.4 RFM计算结果保存3.4.1 保存到excel3.4.2 保存到数据库3.5 RFM计算结果可视化3.6 结果分析&#xff08;营销建议&#xff09;3.…...

消息中间件概述

目录1.为什么学习消息队列2.什么是消息中间件3.消息队列应用场景3.1 应用解耦3.2 异步处理3.3 流量削峰3.4 什么是QPS&#xff0c;PV3.5 什么是PV,UV,PR4. AMQP 和 JMS4.1 AMQP4.2 JMS4.3. AMQP 与 JMS 区别5. 消息队列产品6. RabbitMQ6.1 RabbitMQ简介6.2 RabbitMQ 中的相关概…...

vue和js给后端接口返回的数据(如以json数据为元素的数组)添加新的json字段

文章目录vue和js给后端接口返回的数据&#xff08;如以json数据为元素的数组&#xff09;添加新的json字段1. res为后端接口的响应2. 获取后端接口返回的数据3. 向 tableData 添加字段3.1. 向 tableData 中添加一个新json元素( {"time", "2023-02-09"} )3.…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...