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

生成订单幂等性(防止订单重复提交)

订单唯一性(防止重复下单)方案

重复下单产生原因:

  1. 客户端原因

比如下单的按键在点按之后,在没有收到服务器请求之前,按键的状态没有设为已禁用状态,还可以被按。又或者,在触摸屏下,用户手指的点按可能被手机操作系统识别为多次点击。

  1. 请求超时原因

用户的设备与服务器之间可能是不稳定的网络。这样一个下单请求过去,返回不一定回得来。超时最大的问题是: 从用户的角度,他无法确定下单的请求是还没到服务器,还是已经到了服务器但是返回丢失了。——用户无法区分到底这个单下了还是没下

  1. 用户各种无脑操作

心急的用户可能会重启流程/重启App/重启手机。在这种强制的手段下,任何技术手段都会失效。

解决方案:

方案一:提交订单按钮置灰

防止用户提交,最常规的做法,就是客户端点击下单之后,在收到服务端响应之前,按钮置灰。

前端页面直接防止用户重复提交表单,但网络错误会导致重传,很多RPC框架、网关都有自动重试机制,所以重复请求在前端侧无法完全避免。

当然,这种方案也不是真的没有价值。

这种方案可以在高并发场景下,从浏览器端去拦住一部分请求,减少后端服务器的处理压力,达到过滤流量的效果。

优点:简单。基本可以防止重复点击提交按钮造成的重复提交问题。

缺点:前进后退操作,或者F5刷新页面等问题并不能得到解决。

方案二:请求唯一ID+数据库唯一索引约束

需要客户端在请求下单接口的时候,需要生成一个唯一的请求号:requestId,服务端拿这个请求号,判断是否重复请求。实现的逻辑,流程如下:

当用户进入订单提交界面的时候,调用后端获取请求唯一ID,并将唯一ID值埋点在页面里面。

当用户点击提交按钮时,后端检查这个唯一ID是否用过,如果没有用过,继续后续逻辑;如果用过,就提示重复提交。

最关键的一步操作,就是把这个唯一ID 存入业务表中,同时设置这个字段为唯一索引类型,从数据库层面做防止重复提交。

优点:对于下单流量不算高的系统,可以采用这种 请求唯一ID + 数据表增加唯一索引约束`的方式,来防止接口重复提交!

缺点:并发量太低,10wqps高并发, 这个根本没法满足。

方案三:reids分布式锁+请求唯一ID

随着业务的快速增长,每一秒的下单请求次数,可能从几十上升到几百甚至几万。

面对这种下单流量越来越高的场景,此时数据库的访问压力会急剧上升,数据库会成为整个下单流程的瓶颈。

对于这样的场景,我们可以选择引入缓存中间件来缓解数据库高并发场景下的压力,实现的逻辑,流程如下:

当用户进入订单提交界面的时候,调用后端获取请求唯一 ID,同时后端将请求唯一ID存储到redis中再返回给前端,前端将唯一 ID 值埋点在页面里面。

当用户点击提交按钮时,后端检查这个请求唯一 ID 是否存在,如果不存在,提示错误信息;如果存在,继续后续检查流程。

使用redis的分布式锁服务,对请求 ID 在限定的时间内进行加锁,如果加锁成功,继续后续流程;如果加锁失败,提示说明:服务正在处理,请勿重复提交。

最后一步,如果加锁成功后,需要将锁手动释放掉,以免再次请求时,提示同样的信息;同时如果任务执行成功,需要将redis中的请求唯一 ID 清理掉。

优点:可以满足 10wqps高并发要求。

缺点:每次提交订单的时候,都需要调用服务端获取请求唯一ID

方案四:redis分布式锁+token:

创建订单的时候,用订单信息计算一个哈希值,去生成token ,大致 流程如下:

用户点击提交按钮,服务端接受到请求后,通过规则计算出本次请求唯一ID值

使用redis的分布式锁服务,对请求 ID 在限定的时间内尝试进行加锁,如果加锁成功,继续后续流程;如果加锁失败,说明服务正在处理,请勿重复提交。

最后一步,如果加锁成功后,需要将锁手动释放掉,以免再次请求时,提示同样的信息。

优点减少一次客户端与服务端之间的交互次数,提高下单流程效率

用订单信息计算一个哈希值生成token
    /*** 提交订单*/@PostMapping("/add")public Result add(@RequestBody OrdersVO ordersVO) {StpUtil.checkRoleOr("admin", "user");int hashKey = ordersVO.hashCode();//获取tokenString key = LOCK_KEY + hashKey;//获取锁Boolean isLock = redisTemplate.opsForValue().setIfAbsent(key, hashKey, 60, TimeUnit.SECONDS);if (!isLock) {//未获取到锁 说明订单重复提交 返回错误信息return Result.fail(ShopMsgConstant.REPEAT_SUBMIT.getCode(),ShopMsgConstant.REPEAT_SUBMIT.getMsg());}try {log.info("--------------获取锁成功,生成订单------------------");return goodsOrderService.add(ordersVO);} finally {if (hashKey == (int)redisTemplate.opsForValue().get(key) ){log.info("--------------释放锁------------------");redisTemplate.delete(key);}}}

方案五:技术+产品+运营支持

如果经过上述方案处理,还是会有用户误操作,直到收到两份商品才发现下重了。

在实际设计中,无论多么好的技术,也不可能100%的拦截所有的可能性,必须依靠**技术+产品设计+运营支持**的综合手段才能解决这类问题。

此时就得依靠运营/客服的支持了。

****推荐使用方案四+方案五

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 职场上,不想受气,就要气场强大,以下三招见效
  • Java哈希算法
  • 【RTOS面试题】ISR中可以使用互斥锁和信号量吗?
  • 21. 合并两个有序链表(递归)
  • 代码随想录算法训练营Day22 | Leetcode 77 组合 Leetcode 216 组合总和Ⅲ Leetcode17 电话号码的字母组合
  • 基于内地城市生活垃圾收运场景的路线规划算法
  • 服务器 Linux 的网络信息
  • 【网络安全】探索AI 聊天机器人工作流程实现RCE
  • Unity补完计划 之 SpriteEditer SingleMode
  • 【C++】C++入门基础【类与对象】
  • HslCommunicationDemo各品牌Plc通信测试软件工具
  • 常见cms漏洞之dedecms
  • linux安装weblogic
  • C基础练习(学生管理系统)
  • Golang | Leetcode Golang题解之第316题去除重复字母
  • 345-反转字符串中的元音字母
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • Facebook AccountKit 接入的坑点
  • FineReport中如何实现自动滚屏效果
  • GraphQL学习过程应该是这样的
  • IP路由与转发
  • Java超时控制的实现
  • js
  • Linux Process Manage
  • linux安装openssl、swoole等扩展的具体步骤
  • Mithril.js 入门介绍
  • python学习笔记-类对象的信息
  • Python学习之路13-记分
  • Terraform入门 - 3. 变更基础设施
  • vue-router 实现分析
  • vuex 学习笔记 01
  • 百度地图API标注+时间轴组件
  • 机器学习学习笔记一
  • 每天一个设计模式之命令模式
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 什么软件可以剪辑音乐?
  • Java总结 - String - 这篇请使劲喷我
  • 移动端高清、多屏适配方案
  • ​如何防止网络攻击?
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (javaweb)Http协议
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (八)Flask之app.route装饰器函数的参数
  • (小白学Java)Java简介和基本配置
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .net core 连接数据库,通过数据库生成Modell
  • .Net Core 微服务之Consul(三)-KV存储分布式锁
  • .NET NPOI导出Excel详解
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET6实现破解Modbus poll点表配置文件
  • .NET开源项目介绍及资源推荐:数据持久层
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d