一、什么是接口幂等性

接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用;比如说支付场景,用户购买了商品支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...,这就没有保证接口的幂等性.

二 、哪些情况需要防止

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

三、什么情况下需要幂等

以 SQL 为例,有些操作是天然幂等的。
SELECT * FROM table WHER id=?,无论执行多少次都不会改变状态,是天然的幂等。
UPDATE tab1 SET col1=1 WHERE col2=2,无论执行成功多少次状态都是一致的,也是幂等操作。
delete from user where userid=1,多次操作,结果一样,具备幂等性
insert into user(userid,name) values(1,‘a’) 如 userid 为唯一主键,即重复操作上面的业务,只会插入一条用户数据,具备幂等性。

UPDATE tab1 SET col1=col1+1 WHERE col2=2,每次执行的结果都会发生变化,不是幂等的。
insert into user(userid,name) values(1,'a') 如 userid 不是主键,可以重复,那上面业务多次操
作,数据都会新增多条,不具备幂等性

四、幂等解决方案

1、token机制

1、服务端提供了发送 token 的接口。我们在分析业务的时候,哪些业务是存在幂等问题的,就必须在执行业务前,先去获取 token,服务器会把 token 保存到 redis 中。
2、然后前端在请求业务接口请求时,把token携带过来,一般放在请求头部。
3、服务器判断 token 是否存在 redis 中,存在表示第一次请求,然后删除 token,继续执行业务。
4、如果判断 token 不存在 redis 中,就表示是重复操作,直接返回重复标记给 client,这样就保证了业务代码,不被重复执行。

1.1 使用token机制

1、应用场景,是用户提交订单操作,这个操作就需要保证防止订单重复提交。
2、防止订单重复提交策略方法?
1)数据库层面,将订单表中的订单号设置为唯一索引,防止一个订单出现多条记录的情况。
2)使用token令牌机制,即在提交订单时提交一个token令牌(这个token令牌是后端生成传给前端的),与后端的令牌进行比对(后端的令牌存储在redis中)。

1.2 使用token机制存在几个问题

1、如果令牌比对成功并创建完订单后,再删令牌可不可以,会有什么问题?
不可以,如果在创建订单的过程中,第一个请求进来了,正在创建订单,此时第二个请求也进来了,带着同样的token,比对成功,那么就会有两个相同的订单创建了。

2、如果令牌比对成功后就将令牌删除,再去创建订单可不可以,有什么问题?
不可以,在分布式的环境下,同时进来两个请求,同时比对token,并执行删除令牌的操作这样同样会出现创建两个订单的问题。

// serverToken:后端的令牌
// token:是前端传过来的toikenif(serverToken == token){del(token);server();}

3、如何避免上面的两个问题?

 1、获取令牌2、对比令牌3、删除令牌以上三个操作必须保证原子性,不可分割的如何保证原子性,使用Redis的Lua脚本

Token 获取、比较和删除必须是原子性
(1)redis.get(token) 、token.equals、redis.del(token)如果这两个操作不是原子,可能导致,高并发下,都 get 到同样的数据,判断都成功,继续业务并发执行。
(2)可以在 redis 使用 lua 脚本完成这个操作

if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

2、数据库乐观锁

2.1 数据库乐观锁

这种方法适合在更新的场景中,
update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1根据 version 版本,也就是在操作库存前先获取当前商品的 version 版本号,然后操作的时候带上此 version 号。我们梳理下,我们第一次操作库存时,得到 version 为 1,调用库存服务version 变成了 2;但返回给订单服务出现了问题,订单服务又一次发起调用库存服务,当订单服务传如的 version 还是 1,再执行上面的 sql 语句时,就不会执行;因为 version 已经变为 2 了,where 条件就不成立。这样就保证了不管调用几次,只会真正的处理一次。乐观锁主要使用于处理读多写少的问题

2.2 数据库悲观锁

select * from xxxx where id = 1 for update;

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

3、业务层分布式锁

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

3、各种唯一约束

3.1 数据库唯一约束

1)插入数据,应该按照唯一索引进行插入,比如订单号,相同的订单就不可能有两条记录插入。我们在数据库层面防止重复。
2)这个机制是利用了数据库的主键唯一约束的特性,解决了在 insert 场景时幂等问题。但主键的要求不是自增的主键,这样就需要业务生成全局唯一的主键。
3)如果是分库分表场景下,路由规则要保证相同请求下,落地在同一个数据库和同一表中,要不然数据库主键约束就不起效果了,因为是不同的数据库和表主键不相关。

3.2 redis set 防重

很多数据需要处理,只能被处理一次,比如我们可以计算处理完数据的 MD5 将其放入 redis 的 set,每次处理数据,先看这个 MD5 是否已经存在,存在就不处理。

防止订单重复提交策略方案相关推荐

  1. java服务端实践:防止订单重复提交支付

    来源:cnblogs.com/cjsblog/p/14516909.html 概述 为了防止掉单,这里可以这样处理: 为了防止订单重复提交,可以这样处理: 附上微信支付最佳实践: 概述 如图是一个简化 ...

  2. 支付系统流程以及防止订单重复提交

    支付流程图 如图是一个简化的下单流程,首先是提交订单,然后是支付.支付的话,一般是走支付中心,然后支付中心与第三方支付渠道(微信.支付宝.银联)交互,支付成功以后,异步通知支付中心,支付中心更新自身支 ...

  3. 分布式锁防止订单重复提交_防止表单重复提交看这里!!!

    要解决重复提交这事,先要知道什么是重复提交 假如用户的网速慢,用户点击提交按钮,却因为网速慢,而没有跳转到新的页面,这时的用户会再次点击提交按钮,举个例子:用户点击订单页面,当点击提交按钮的时候,也许 ...

  4. java订单重复提交_java表单重复提交常用解决办法

    最近在看些基础的东西,顺便做下笔记.相信大家在平时网页使用中,经常会有按钮重复点击,然后点不动刷新,还有当网络延时比较厉害点了没反应在点击的重复提交.为了避免这种情况,总结了一下4点处理方案 表单重复 ...

  5. springboot 订单重复提交_Spring Boot (一) 校验表单重复提交

    一.前言 在某些情况下,由于网速慢,用户操作有误(连续点击两下提交按钮),页面卡顿等原因,可能会出现表单数据重复提交造成数据库保存多条重复数据. 存在如上问题可以交给前端解决,判断多长时间内不能再次点 ...

  6. springboot 订单重复提交_防止表单重复提交(springboot,redis)

    我们在web项目中经常需要在后台对用户提交的表单进行校验防止重复提交.下面通过springboot的aop.redis来解决表单重复提交的问题. 通过在controller加上CheckSubmitF ...

  7. 幂等性的研究及后台验证短时间内同一申请是否重复提交的方案

    幂等性的研究及实例应用 引入: 这段时间在做新渠道的接入,把以前的核心拿过来copy一份进行改造,在进行代码重读的时候,发现了一个好玩的东西,在申请入件的时候,需要经过一步校验,注释上写的是,对于短时 ...

  8. springboot 订单重复提交_瞬间几千次的重复提交,我用Spring Boot+Redis扛住了

    在实际的开发项目中,一个对外暴露的接口往往会面临,瞬间大量的重复的请求提交,如果想过滤掉重复请求造成对业务的伤害,那就需要实现幂等! 我们来解释一下幂等的概念: 任意多次执行所产生的影响均与一次执行的 ...

  9. 服务端如何防止订单重复支付!

    点击关注公众号,Java干货及时送达 作者:废物大师兄 www.cnblogs.com/cjsblog/p/14516909.html 如图是一个简化的下单流程,首先是提交订单,然后是支付.支付的话, ...

最新文章

  1. Windows配置远程访问的Jupyter Notebook服务器
  2. python中分支结构有几种各有什么特点_「武鹏有课」Python分支结构的种类
  3. RHEL6.3配置Apache服务器(4) 基于用户的访问控制
  4. ostream作为函数返回值_Go语言入门必知教程-函数
  5. 利用ffmpeg转换mp4文件
  6. 牛客练习赛51-记录
  7. mongodb 持久化 mysql_最详细的python爬虫指南(四):持久化操作(mongoDB、mysql)...
  8. Entity Framework 4 in Action读书笔记——第四章:使用LINQ to Entities查询:排序和连接数据...
  9. 阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第3节 两种获取Stream流的方式_7_Stream流中的常用方法_limit...
  10. SGD ,Adam,momentum等优化算法比较
  11. PHP电子合同对接流程,电子合同订立程序步骤
  12. 【FPGA教程案例89】编译码2——使用vivado核实现RS信道编译码
  13. 业务流程驱动的数字化转型,中小微企业开启转型的最简单方法论
  14. PPT文件带有打开密码怎么解决
  15. android分辨率2k3k4k,android 不同分辨率适配
  16. 移动开发技术——近场通信
  17. ERLANG日期与时间
  18. 小旋风蜘蛛池采集工具教程分享
  19. 转:拥抱挣扎:创造组织的同时,也创造了崭新的自我
  20. 闪蝶-COBOL代码分析工具

热门文章

  1. ffprobe-命令行详解
  2. 中国光学十大进展|每秒4万亿帧相机,把光拍成黑客帝国子弹
  3. IntelliJ IDEA for Mac (java开发集成环境) v2021.3
  4. LINUX 系统:部署达梦企业管理工具-DEM
  5. 阿里云服务器+docker+jenkins+nginx+自定义访问路径
  6. 基于状态机实现XMODEM和YMODEM协议
  7. 工商银行拥抱互联网的“e-难题”
  8. 高中信息技术教学大纲
  9. 如何处理低概率出现的bug???
  10. vivox20Android版本8.0,四月份可升级!vivo官方公布7款机型升级安卓8.0适配计划