接口幂等性介绍 SpringCloud下接口幂等性的解决方案 Token令牌机制实现_彷徨的我第一次尝试的博客-程序员信息网_springcloud 接口幂等性

技术标签: spring boot  java  SpringCloud 学习  分布式  redis  

接口幂等性介绍 SpringCloud下接口幂等性的解决方案 Token

场景:在分布式系统之间,当给表单提交数据或分布式系统之间的相互调用,一个方法可能会执行多次(用户重复提交),需要保证执行多次(提交多次)和执行一次的结果相同,保证接口的幂等性

什么是接口幂等性?

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

举例:比如说支付场景,用户购买了商品支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,流水记录也变成了两条.此时就没有保证接口的幂等性.

哪些情况下需要保证接口幂等性 防止流水错误

  • 用户多次点击提交按钮
  • 用户页面回退再次提交
  • 微服务之间互相调用,由于网络问题,导致请求失败.feign触发重试机制
  • 其他业务情况

幂等解决方案

1.数据库层面

1.1 添加UNIQUE索引

将数据库中的字段添加索引,设置为唯一字段,实现幂等

在这里插入图片描述

1.2 数据库的悲观锁

select * from xxx where id = 1 for update
  • 悲观锁使用时一般伴随事务一起使用, 数据锁定时间可能会很长,需要根据实际情况选用
  • 另外要注意的是,id字段一定是主键或者唯一索引,不然可能造成锁表的结果,处理起来非常麻烦

1.3 数据库的乐观锁 (更新场景中适用)

update table set field=field+1 , version = version+1 where id=1 and version = 1
  • 根据version版本,也就是在操作库存前先获取当前商品的version版本号,然后操作的时候带上此version号。
  • 我们第一次操作库存时,得到version为1,调用库存服务version变成了2
  • 当返回给订单服务出现了问题,订单服务又一次发起调用库存服务,当订单服务传如的version还是1,再执行上面的sgl语句时,就不会执行
  • 乐观锁主要使用于处理读多写少的问题

2.后端业务层面实现

2.1token机制

实现原理:

  • 服务端提供发送token的接口.在需要幂等问题的业务执行前,先去获取token,服务器会把token保存在redis中.(原子性)

    •  //TODO 放重复提交令牌  幂等性
              String token = UUID.randomUUID().toString().replace("-", "");
             stringRedisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX+memberResVo.getId(),token,30, TimeUnit.MINUTES);
      
  • 然后调用业务接口请求时,把token携带过去,一般放在请求的头部.

    • <input type="hidden" th:value="${orderConfirmData.getOrderToken()}" name="orderToken">
      			<button class="tijiao">提交订单</button>
      
  • 服务器判断tiken是否存在redis中,存在表示第一次请求,然后删除token,继续执行业务.(使用lua脚本保证原子性)

    • //1.验证令牌[令牌的对比和删除必须原子性]
              String orderToken = vo.getOrderToken();
              String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                      "then " +
                      "   return  redis.call('del', KEYS[1])" +
                      "else " +
                      "   return 0 " +
                      "end";
              /**
               * 使用lua脚本原子验证和删除令牌 判断参数key[1]的值和传入的参数avg[1]是否相等,相等则删除
               * execute(RedisScript<T> script, List<K> keys, Object... args)
               * keys: redis中的键名
               * args: 对比的参数
               * 返回类型为Long
               * 返回 0:表示失败
               *     1:表示成功
               */
              Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(luaScript, Long.class),
                      Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResVo.getId()),
                      orderToken);
              if(result == 1){
              
                  //验证成功,处理业务
                  return orderSubmitResVo;
              }else {
              
                  //验证失败
                  return null;
              }
      
  • 如果判断token不存在redis中,即表示为重复操作,直接返回重复标记给客户端,保证业务代码不被重复执行.

缺点:

  • 先删除token还是后删除token;

    • 先删除可能导致,业务还没执行就闪断,后面的请求任然无法执行
    • 后删除也可能出现业务成功后再删除前闪断.
  • token的获取,比较和删除必须是原子的(lua脚本实现)

    • 如果操作不原子,高并发下可能多个业务同时判断成功,都执行

    • String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                      "then " +
                      "   return  redis.call('del', KEYS[1])" +
                      "else " +
                      "   return 0 " +
                      "end";
      

2.2 分布式锁(影响性能)

​ 如果多个机器可能在同一时间同时处理相同的数据,比如多台机器定时任务都拿到了相同数据处理,我们就可以加分布式锁,锁定此数据,处理完成后释放锁。获取到锁的必须先判断这个数据是否被处理过。

分布式锁+分布式下的缓存问题 使用redis(redisson) 实现分布式锁

2.3 全局请求唯一id

​ 调用接口时,生成一个唯一的id,redis将数据保存到集合中(去重),存在即处理过.可以使用nginx设置每一个请求的唯一id

proxy_set_header X-Request-Id $request_id;

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44634197/article/details/108647258

智能推荐

Ubuntu之Pycharm找不到pip解决方案_Quincy379的博客-程序员信息网_pycharm没有pip

这个问题奇怪的很,以前电脑好好的,在新电脑上(Ubuntu)安装模块都是失败的,t提示找不到pip,我就纳了闷了,然后搜到如下链接: https://askubuntu.com/questions/748264/error-python-packaging-tool-pip-not-found2.这条命令就搞定了,搞了好久,还是老外的解决方案靠谱啊! sudo apt i...

魅族18关闭桌面悬浮球方法步骤_爱学习的小兔子的博客-程序员信息网

现在用户们都已经非常适应全面屏手机的使用了。但刚买的手机桌面还是会有一个悬浮导航键。很多小伙伴想要关闭却不知道方法。于是今天换换就给大家介绍一下魅族18关闭悬浮球的方法吧!魅族18关闭悬浮球步骤1、通常这些手机使用的更改都是在设置里面操作。2、进入设置后。找到辅助功能。3、在辅助功能里我们就可以看见悬浮球选项。4、选择悬浮球右侧按钮点击即可关闭。5、当然。还有一种更简单的方法便是用户们下拉菜单栏。点击悬浮球选项就能关闭。...

解决cmd中,javac提示:javac不是内部或外部命令,但是运行java、java-version正常的问题_小猴爷的博客-程序员信息网_javac' 不是内部或外部命令,也不是可运行的程序

没什么其他原因,要不就是你安装JDK不完整,要不就是你配置环境变量错误。配置环境变量:1.新建一个系统变量。变量名:JAVA_HOME变量值:D:\Java其中变量名可以随便你写,变量值必须是你安装JDK的路径2.系统变量(CLASSPATH),没有就自己新建一个变量名:CLASSPATH变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_

HTML页面实现自动刷新的2种方式_幕尘枫的博客-程序员信息网

1.页面自动刷新:把如下代码加入<head&amp;gt;区域中<meta http-equiv=&quot;refresh&quot; content=&quot;20&quot;&amp;gt;//其中20指每隔20秒刷新一次页面2.页面自动刷新js版<script language=&quot;JavaScript&quot;&amp;gt;function myrefresh(){window.location.reload();}setTimeout('myrefre...

边缘计算是云计算能力向边缘侧和用户侧的下沉和延展_美林数据Tempodata的博客-程序员信息网_边缘计算+下沉到用户侧

边缘,是计算机接触世界的地方,从此大数据、人工智能不再高高在上,而是转变为切实在工厂、煤炭、油井、配网等现场发挥价值、创造收益的智能体。美林数据专家团队从边缘计算背后的收益逻辑出发展开讨论,希望能给正处在数字化转型过程中的企业带来一些思考。

eclipse gradle buildship 执行build任务提示Could not find tools.jar_aarontang2025的博客-程序员信息网

这个问题纠结了我2个小时,一开始以为是buildship插件的问题,试了几遍都跟原来一样,使用gradle命令行构建正常,buildship 中执行task任务就报错。下面是问题的过程及解决方法eclipse中执行gradle build task提示失败控制台报错提示Could not find tools.jar解决方法Gradle

随便推点

运算符重载及STL总结_请给我一个豆豆的博客-程序员信息网_stl运算符重载

一:运算符重载1、基本概念:运算符重载使得用户自定义的数据以一种更简洁的方式工作。(1)声明与定义格式类内声明:class X{返回类型 operator运算符(形参表);}类外定义:返回类型X::operator运算符(形参表){函数体}(2)双目运算符重载为成员函数,形参表中只有一个参数,作为运算符的右操作数,当前对象作为左操作数,通过this指针隐式传递给函数。用重载运算符加号来实现复数的加...

notepad++常用配置_sunpro518的博客-程序员信息网_notepad配置

win10环境下,文本编辑器最喜欢的还是notepad++。相比sublime text /ultraEdit/notepad 等,兼具小巧快捷方便。换来换去,还是notepad++用的习惯。一般来说,notepad++辅助文档编辑和初步代码编辑器,有这么几项配置用起来还是很舒服的。快捷键:快捷键配置如图所示。一般也都有了,就是代码注释的快捷键和一般的代码编辑器不同,用起来不习惯,就改一下。其他也可以按照自己的习惯修改。遇到有冲突的 地方,修改一下就好了。主题:notepad++支

sonar 扫描vue目录_vue+elementUI项目实战1_weixin_39664136的博客-程序员信息网

可视化新建项目打开可视化面板vue ui创建项目可以保存为预设,下次使用此预设时就不需要再次配置了创建完成后我们可以看到他的文件结构vue3初体验入口文件在public中,不在根目录配置全局变量 根目录新建vue.config.js// Vue.config.js 配置选项module.exports = { // 选项 // 基本路径 vue....

大学生可参加的含金量比赛有哪些?_hope lucky的博客-程序员信息网

大学生可参加的含金量比赛有哪些?全国高校学科竞赛排行榜竞赛项目1 中国“互联网+”大学生创新创业大赛https://cy.ncss.org.cn/2 “挑战杯”全国大学生课外学术科技作品竞赛http://www.tiaozhanbei.net/3 “创青春”中国大学生创业计划大赛http://www.chuangqingchun.net/4 ACM-ICPC国际大学生程序设计竞赛http://acm.cumt.edu.cn/5 全国大学生数学建模竞赛http://www.mcm.edu

解析「觞定关中.何干」 美学文创白酒品类_中国品牌网全球ChinaBrand的博客-程序员信息网

“关中形胜之地,而以弱才小儿守之,非经远之规也”,《资治通鉴》中有关刘裕的讨论,言辞之间,自有一种指点江山之豪迈之气。“关中,形胜之地”,关中,总是与豪迈有一种切割不断的关系。但凡对于《资治通鉴》有过多次阅读者,无不留下深刻印象。也正是因为这些深刻印象,酒产业链C4B业态互联网酒业「心直酒快」才会孵化出这个品牌「觞定关中」之「Shang觞定关中.何干3两3」。该品牌获得专业品牌创投机构Fin...

复旦计算机系本硕连读几年,本硕连读要读几年 如何报考_忠北小石头的博客-程序员信息网

本硕连读是本科毕业后保送硕士接着读 ,一般本科需要4年,硕士需要3年,总共7年。前提是在本科阶段没有挂科或违纪行为。本硕连读如何报考通过高考直接考,本硕连读的专业名字上面就会注明本硕连读这四个字,跟其他专业招生是一样的,你分数够报这个专业就行了,一般是医学类的有本硕连读。本硕连读分数是不是比一般本科分数线高这个是肯定的,而且本硕连读的专业与学校一般都会比较好,像临床等专业一般要比本专业分数还要高,...

推荐文章

热门文章

相关标签