Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何防订单重复提交策略方法

如何防订单重复提交策略方法

原创
作者头像
Tinywan
修改于 2018-09-25 01:57:15
修改于 2018-09-25 01:57:15
2.1K0
举报
文章被收录于专栏:开源技术小栈开源技术小栈

#### [原文链接:https://www.cnblogs.com/jett010/articles/9056567.html](https://www.cnblogs.com/jett010/articles/9056567.html)

### 背景

在业务开发中,我们常会面对防止重复请求的问题。当服务端对于请求的响应涉及数据的修改,或状态的变更时,可能会造成极大的危害。重复请求的后果在交易系统、售后维权,以及支付系统中尤其严重。

前台操作的抖动,快速操作,网络通信或者后端响应慢,都会增加后端重复处理的概率。前台操作去抖动和防快速操作的措施,我们首先会想到在前端做一层控制。当前端触发操作时,或弹出确认界面,或disable入口并倒计时等等,此处不细表。但前端的限制仅能解决少部分问题,且不够彻底,后端自有的防重复处理措施必不可少,义不容辞。

在接口实现中,我们常要求接口要满足幂等性,来保证多次重复请求时只有一次有效。

查询类的接口几乎总是幂等的,但在包含诸如数据插入,多模块数据更新时,达到幂等性会比较难,尤其是高并发时的幂等性要求。比如第三方支付前台回调和后台回调,第三方支付批量回调,慢性能业务逻辑(如用户提交退款申请,商家同意退货/退款等)或慢网络环境时,是重复处理的高发场景。

### 尝试

这里针对“用户提交退款申请”的例子,说明一下尝试过的防重复处理方法的效果。后端防重复处理的方式,我们先后尝试了三种:

#### (1)基于DB中退款订单状态的验证

这种方式简单直观,从DB查询出来的退款详情(包括状态)往往还可以用在后续逻辑中,没有花额外的工作专门应对重复请求的问题。

这种查询状态后进行验证的逻辑,从代码上线后就一直存在于所有含状态的业务逻辑处理中,必不可少。但对于防重复处理效果并不好:在前端添加防重复提交前,每周平均在25笔;前端优化后,每周降到7笔。这个数量占总退款申请数的3%%,一个仍然无法接受的比例。

理论上,任意次请求只要在数据状态更新之前都完成了查询操作,则业务逻辑的重复处理就会发生。如下图所示。优化的方向是减少查询到更新之间业务处理时间,可降低空档期的并发影响。极致情况下如果查询和更新变成了原子操作,则就不存在我们当前的问题。

![](https://img2018.cnblogs.com/blog/1021265/201809/1021265-20180917173747789-386317460.png)

####(2)基于缓存数据状态的验证

Redis存储查询轻量快速。在request进来的时候,可以先记录在缓存中。后续进来的request每次进行验证。整个流程处理完成,清除缓存。以退款为例子:

* I. 每次退款发起申请,读取缓存中是否有以orderId为key的值

* II. 没有,则往缓存中写入以orderId为key的value

* III.有,则说明有该订单的退款正在进行。

* IV. 操作完清缓存,或者缓存存值的时候设置生命周期

与1)的发放相比,数据库换成响应更快的缓存。但是仍然不是原子操作。插入和读取缓存还是有时间间隔。在极致的情况下还是存在重复操作的情况。此方法优化后,每周1笔重复操作。

![](https://img2018.cnblogs.com/blog/1021265/201809/1021265-20180917173805925-1949274645.png)

####(3)利用唯一索引机制的验证

需要原子性操作,想到了数据库的唯一索引。新建一个TradeLock表:

```

CREATE TABLE `TradeLock` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`type` int(11) NOT NULL COMMENT '锁类型',

`lockId` int(11) NOT NULL DEFAULT '0' COMMENT '业务ID',

`status` int(11) NOT NULL DEFAULT '0' COMMENT '锁状态',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Trade锁机制';

```

* 每次request进来则往表里面插入数据:

> 成功,则可以继续操作(相当于获取锁);

> 失败,则说明有操作在进行。

* 操作完成后,删除此条记录。(相当于释放锁)。

目前已经上线,等待下周的数据统计。

![](https://img2018.cnblogs.com/blog/1021265/201809/1021265-20180917173814544-1871115286.png)

####(4)基于缓存的计数器验证

由于数据库的操作比较消耗性能,了解到redis的计数器也是原子性操作。果断采用计数器。既可以提高性能,还不用存储,而且能提升qps的峰值。

还是以订单退款为例子:

* 每次request进来则新建一个以orderId为key的计数器,然后+1。

> 如果>1(不能获得锁): 说明有操作在进行,删除。

> 如果=1(获得锁): 可以操作。

* 操作结束(删除锁):删除这个计数器。

> 要了解计数器,可以参考:[http://www.redis.cn/commands/incr.html](http://www.redis.cn/commands/incr.html)

![](https://img2018.cnblogs.com/blog/1021265/201809/1021265-20180917173829338-1797651582.png)

## 总结:

PHP语言自身没有提供进程互斥和锁定机制。因此才有了我们上面的尝试。网上也有文件锁机制,但是考虑到我们的分布式部署,建议还是用缓存。在大并发的情况下,程序各种情况的发生。特别是涉及到金额操作,不能有一分一毫的差距。所以在大并发要互斥的情况下可以考虑3、4两种方案。

> 爱迪生尝试了1600多种材料选择了钨丝发明了灯泡,实践出真知。遇到问题,和问题斗争,最后解决问题是一个最大提升自我的过程,不但加宽自己的知识广度,更加深了自己的技能深度。达到目标之后的成就感更是不言而喻。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
京东电商下单黄金链路:防止订单重复提交与支付的深度解析
在电商领域,尤其是在像京东这样的大型电商平台中,防止订单重复提交与支付是一项至关重要的任务。这不仅关乎用户体验,还直接影响到平台的运营效率和信誉。本文将深入探讨京东电商下单黄金链路中如何防止订单重复提交与支付的解决方案,从背景、业务场景、功能、底层实现原理以及具体措施等方面进行详细讲解,并结合Java代码进行分析。
小马哥学JAVA
2024/10/27
3080
防止数据重复提交的6种方法(超简单)!
前端拦截是指通过 HTML 页面来拦截重复请求,比如在用户点击完“提交”按钮后,我们可以把按钮设置为不可用或者隐藏状态。
磊哥
2020/07/20
5.5K0
防止数据重复提交的6种方法(超简单)!
接口服务中的幂等性设计和防重保证,详细分析幂等性的几种实现方法
由于ABA问题会导致乐观锁存在失效的情况,只要保证version值自增就不会出现ABA的问题
攻城狮Chova
2022/01/22
5060
接口服务中的幂等性设计和防重保证,详细分析幂等性的几种实现方法
幂等和防重
系统的幂等承诺是只要调用接口成功,外部多次调用对系统的影响是一致的.当一个接口(或服务)声明为幂等,应看作调用失败是常态,并且失败之后必然会重试。
leobhao
2022/06/28
8940
面试:如何保证接口的幂等性?常见的实现方案有哪些?
在说幂等性之前,我们先来看一种情况,假如老王在某电商平台进行购物,付款的时候不小心手抖了一下,连续点击了两次支付,但此时服务器没做任何验证,于是老王账户里面的钱被扣了两次,这显然对当事人造成了一定的经济损失,并且还会让用户丧失对平台的信任。而幂等性问题说的就是如何防止接口的重复无效请求。
JAVA日知录
2021/04/07
7.5K0
面试:如何保证接口的幂等性?常见的实现方案有哪些?
如何防止订单二次重复支付?
在电商平台和支付系统中,防止订单二次重复支付是一个至关重要的功能。以下是一些常见的策略和技术手段,用于确保订单支付的幂等性和一致性。
用户11397231
2024/12/18
1510
如何防止订单二次重复支付?
架构设计 | 接口幂等性原则,防重复提交Token管理
编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。就是说,一次和多次请求某一个资源会产生同样的作用影响。
知了一笑
2020/05/28
1.5K0
大厂必问 · 如何防止订单重复?
在电商系统或任何涉及订单操作的场景中,用户多次点击“提交订单”按钮可能会导致重复订单提交,造成数据冗余和业务逻辑错误,导致库存问题、用户体验下降或财务上的错误。因此,防止订单重复提交是一个常见需求。
不惑
2024/09/24
7390
大厂必问 · 如何防止订单重复?
接口幂等设计探索实践
幂等性原本是数学上的概念,即使公式:f(x)=f(f(x)) 能够成立的数学性质。用在编程领域,则意为对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的、或者说是符合预期的。
王炸
2020/11/25
5030
接口幂等设计探索实践
解决支付订单,重复提交问题!
如图是一个简化的下单流程,首先是提交订单,然后是支付。支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互,支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。
良月柒
2021/10/14
2.1K0
SpringBoot接口防抖(防重复提交)的一些实现方案
作为一名老码农,在开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。
程序员皮皮林
2024/09/12
2580
SpringBoot接口防抖(防重复提交)的一些实现方案
谈谈高并发下的幂等性处理
Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
Bug开发工程师
2018/07/23
3K0
分布式服务 API 的幂等设计方案 & Spring Boot + Redis 拦截器实现实例
假如你有个服务提供一个接口,结果这个服务部署在了5台机器上,接着有个接口就是付款接口。
一个会写诗的程序员
2021/04/02
8500
深入理解为什么要设计幂等性的服务
HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
搜云库技术团队
2019/10/18
1.4K0
【第十八篇】商城系统-订单中心设计解决方案
  我们需要把相关的静态资源拷贝到nginx,然后动态模板文件拷贝到order项目的templates目录下,然后调整资源的路径。在网关中设置对应的路由即可。
用户4919348
2022/10/04
7390
【第十八篇】商城系统-订单中心设计解决方案
分布式接口防抖终极解决方案,如何避免重复提交!
防抖(Debouncing)是一种编程技术,用于控制事件处理函数的执行频率。在用户与界面交互频繁的场景中,比如连续滚动、连续输入等,如果每次交互都触发事件处理函数,可能会导致性能问题或不必要的数据库操作。
Tinywan
2024/07/05
5460
分布式接口防抖终极解决方案,如何避免重复提交!
系统设计——幂等性与解决方案
摘要 幂等概念来自数学,表示N次变换和1次变换的结果是相同的。这里讨论在某些场景下,客户端在调用服务没有达到预期结果时,会进行多次调用,为避免多次重复的调用对服务资源产生副作用,服务提供者会承诺满足幂等。HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的副作用(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
终有救赎
2023/10/16
4920
系统设计——幂等性与解决方案
瞬间几千次的重复提交,我用Redis 扛住了...
在实际的开发项目中,一个对外暴露的接口往往会面临,瞬间大量的重复的请求提交,如果想过滤掉重复请求造成对业务的伤害,那就需要实现幂等!
开发者技术前线
2020/11/23
4380
瞬间几千次的重复提交,我用Redis 扛住了...
面试官:如何保证接口幂等性?一口气说了12种方法!
幂等性原本是数学上的概念,用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。
程序员大彬
2022/12/22
2K0
面试官:如何保证接口幂等性?一口气说了12种方法!
Spring Boot+Redis 扛住,瞬间千次重复提交(实例)
在实际的开发项目中,一个对外暴露的接口往往会面临,瞬间大量的重复的请求提交,如果想过滤掉重复请求造成对业务的伤害,那就需要实现幂等!
搜云库技术团队
2019/12/24
2.5K0
推荐阅读
相关推荐
京东电商下单黄金链路:防止订单重复提交与支付的深度解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档