如何避免下重复订单

234 篇文章 4 订阅
订阅专栏

如何避免下重复订单

 

电子交易的一个很基本的问题,就是避免用户下重复订单。用户明明想买一次,结果一看下了两个单。如果没有及时发现,就会带来额外的物流成本和扯皮。对商家的信誉也不好看。

从技术上看,这是一个分布式一致性问题;但实际上,技术无法100%解决这类问题,得结合多种手段综合处理。这里就来说道说道。

为啥会下重了呢?

  • 原因1:客户端bug

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

嗯,谁能保证客户端不偶尔出个什么bug 呢。

  • 原因2: 超时

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

这样在等待一个超时后,UI可能会提示用户下单超时,请重复再试。

下单超时

  • 原因3: 用户的App闪退/人工强退,之后重新打开重新下单

也许可以使用一些技术手段避免用户下重单,但是心急的用户可能会重启流程/重启App/重启手机。在这种强制的手段下,任何技术手段都会失效——用户压根就不让你的技术执行,你怎么玩?

在这些条件下,如何避免用户多下了一笔订单呢?

用幂等防止重复订单

在技术方面,这是一个分布式一致性的问题,即客户端和服务器端对某个订单是否成功/失败达成一致。防止重单的关键是使用一个由客户端生成的,可用于避免重复的key,俗称dedup key(deduplicate key之意)。这个key可以用任意可以保证全局唯一性的方式生成,比如uuid。客户端和服务器需要使用这个dedup key作为串联条件,一起解决去重问题。

客户端的流程

客户端需要实现这样一个下单界面。用户点击【确认下单】时,应该产生一个独一无二的dedup key,连定订单数据发送给服务器端。在服务器返回之前,该界面应该一直等待,直到服务器响应成功/失败或者超时发生(比如15秒后,收不到服务器响应)。如果超时发生,应该向用户提示是否重试下单或者退出该界面。当用户点击【重试】时,应该用刚刚生成的dedup key来再次发送下单请求——如果用户一直不退出这个流程,每次用户点击重试,都应该用这个dedup key来重试下单,直到服务器正常返回,或者用户放弃返回。

下单的客户端流程

后端数据表设计

后端在订单数据表中,需要增加dedup_key这列,并设置唯一约束

 

create table order(
  # ...
  dedup_key varchar(60) not null comment 'key to pretend order duplication',
  # ...
  unique uniq_dedup_key(dedup_key)
);

下单的实现

在实现下单逻辑时,基于该dedup_key实现一个"create-or-get"语义的下单接口——简单说就是

 

如果带有指定dedup_key的订单已经存在,则直接返回;否则,用该dedup_key下单。

用伪代码表示大概是:

 

@Transactional
Order createOrder(Integer userId, String prodCode, Decimal amount, String dedupKey) {
  try {
    String orderId = createOrder(userId, prodCode, amount, deupKey); // insert a new order
    Order order = getOrderById(orderId); // read order from db
    order.setDuplicated(false);
    return order;
  } catch(UniqueKeyViolationException e) {
    // if duplicated order has existed
    Order order = getOrderByDedupKey(dedupKey);
    order.setDuplicated(true);
    return order;
  } catch (Exception e) {
    // hanlde other errors and rollback transaction ...
  }
}

这时,这段下单代码总是能返回一个订单(除非发生一些DB挂了之类的错误),要么是新创建的,要么就是一个已经存在的单。注意,最好在订单里增加一个属性(比如例子中用“duplicated”)来表示这个订单是这次新生成的,还是因为幂等而直接返回的。这样前端可以有针对性的对这两种情况提示不同的文案。

技术搞定幂等就足够了吗?

上面的流程没有考虑一种情况,就是用户中途强制退出客户端,或者直接点击【返回】回到产品页,重新走下单流程。这个时候客户端就无法判断用户到底是想重新下单,还是想第二次下单。此时,可以从产品设计上考虑一下。

比如,在客户端缓存一个表,记录所有没有确认结果的订单。

 产品代码产品数量金额dedup key
未确认订单1AAA11000xxx-yyy-zzz
未确认订单2BBB2500.00Aaa-bbb-ccc
...    

通过这个表,我们可以一下用户的意图。比如,如果用户重新提交了一笔订单,其产品代码、金额与表中记录的某条完全一致,就可以提示一下用户:

提示一下用户是不是下重了

如果用户想重试,可以继续用表中对应记录的dedup key重新发起下单。

这样不是绝对准确的,仅仅是尽量的减少用户误操作的可能性。当然,在产品设计上可以能出于用户交互简化,不一定真的会这样做。这就需要其他机制来配合,比如“通知”。

通知

一旦服务器下单成功,可以通过某种通知机制(如APNS、Websocket)主动将订单推送至客户端,强行让客户端重新拉取最新的订单信息,并配合“未确认订单”表,以通知Badge/弹框等方式提示用户刚刚一笔状态未知的订单成功/失败了。

另外一种手段就是,服务器端实时扫描用户的下单数据,一旦发现可能的重单,就立刻通知客服主动联系用户,及时处理问题。

如果还拦不住……

经过层层阻拦,可能还是会有用户误操作,直到收到两份商品才发现下重了。此时就得依靠运营/客服的支持了。提供用户申诉的手段,让用户提出哪些订单是重复的,并且由销售系统店家、商品提供者和买家三方共同根据用户操作的记录来协商如何处理。我们需要让技术帮助让这种人工处理的几率尽量小。因为每次处理都会耗费较大的人工成本,和一些运营费用(比如赔款、小礼品等等)。

这么麻烦,有必要吗?

这要分业务场景,对于很多电商来讲可能不是必要的。因为从用户下单到订单被审核处理进入到发货阶段需要一定的时间(可能是半小时~1小时),并且一定是支付成功后才会开始进行下一步流程。在这个时间段,用户大概率能从网络错误中恢复过来,自行区分是否下重了。配合客服主动提示,会极大的降低出问题的概率。

但是对于理财服务来说,这种去重就非常必要了。因为

  • “下单+支付”。用户购买理财往往是“下单+支付”一起执行,不可以单独下单/单独支付
  • 用户的入金可能很大。例如数万,数十万
  • 准确性丢失。如果一旦下重了,有可能影响用户的投资资金配置的准确性。
  • 撤销难。部分理财产品存在下单不可撤销的问题;或者即便撤销,资金也无法立刻回款。等到回款,可能这个购入机会就错过去了。例如对于基金交易,错过1个交易日,价格就会发生变动。

基于这些特性,在理财产品中,就要竭尽全力的去重。

结论

以上所讲是处理重复订单问题的一般方法。你可以注意到,无论多么好的技术,也不可能100%的拦截所有的可能性,必须依靠技术+产品设计+运营支持的综合手段才能解决这类问题。

另外,本文还没涉及到关于订单支付(支付也可能重复哦)带来的进一步的复杂性,也没有讨论在高并发情况下的性能优化,仅仅讨论下单本身的问题。所以可以想象一下现实中的交易业务比这里的说的要复杂得多。

本文介绍的原理也不仅仅适用于防止下重复订单,而是可以应用到任何需要“创建一个不应该重复资源”的场景,比如“向用户发一条通知”,“触发一次不能重复的批处理任务“……


链接:https://www.jianshu.com/p/e618cc818432

 

其它相对简单但并不完美的解决办法

比如客户端与服务端没有用一个唯一标识来做请求的标识符,这是要怎么来解决重复下单问题呢?

1 客户端在用户点击按钮发起请求后,按钮要置为不可用

2 在服务端处理过程中,要加锁,如果是单实例的加本地缓存锁即可,多个实例最好加分布式锁

部分代码如下:

 var isdoing = Gd.CacheApi.UserCapital.GetUserConsumeLockCache(userId);
                    if (isdoing < 1)
                    {
                        //加锁
                        Gd.CacheApi.UserCapital.SetUserConsumeLockCache(userId);

                        var result = UserConsume(userId, consumeTypeId, consumeMoney, isAnonymous, wishContent, consumeNums, isShowWish, toUserName);
                        call.Result = result;
                        if (result.ResultCode != 0)
                        {
                            call.Error = result.ResultMsg;
                        }
                        else
                        {
                            call.Error = "";
                        }
                        //移除锁
                        Gd.CacheApi.UserCapital.RemoveUserConsumeLockCache(userId);
                    }

此种方法可以有效减少出现重复单,但并不完美,相对完美的还是上面的方案!

--- end ---


 

接口防止重复提交,订单避免重复下单
Stone.鱼儿的博客
08-15 2263
接口防重
Java怎么避免重复订单_javaEE高并发之如何产生唯一不重复订单
weixin_33477290的博客
02-27 2630
javaEE高并发之如何产生唯一不重复订单号1.方案一:使用进程ID,线程ID,IP,MAC地址和时间戳进行拼接产生订单号(1)如果没有并发,订单号只在一个线程内产生,那么由于程序是顺序执行的,不同订单的生成时间戳正常不同,因此用时间戳+随机数(或自增数)就可以区分各个订单。(2)如果存在并发,且订单号是由一个进程中的多个线程产生的,那么只要把线程ID添加到序列号中就可以保证订单号唯一。//jav...
如何防止重复下单
三分恶的博客
07-30 3847
大家好,我是老三,上一篇我们聊了这篇和大家聊聊如何防止重复下单,文章很短,大概只需要几分钟阅读。
聊聊大厂都怎么防止重复下单
犬小哈
07-21 56
来源:blog.csdn.net/qq_33589510/article/details/104954137???? 欢迎加入小哈的星球,你将获得:专属的项目实战 /1v1 提问/Java 学习路线 /学习打卡/每月赠书/社群讨论新项目:《从零手撸:仿小红书(微服务架构)》正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK ...
如何防止重复下单
qq_51240148的博客
04-19 1539
如何防止重复下单
如何防止重复提交订单
个人主页
10-09 1325
产生的原因 - 一种是由于用户在短时间内多次点击下单按钮,或浏览器刷新按钮导致。 - 另一种则是由于Nginx或类似于SpringCloud Gateway的网关层,进行超时重试造成的。 - 由于网速等原因造成页面卡顿,用户重复刷新提交页面 - 黑客或恶意用户使用 postman 等网络工具,重复恶意提交表单
如何防止用户连续下单两次误操作
weixin_45448080的博客
01-05 1053
使用缓存机制来记录用户的请求,一旦发现有重复的请求,可以及时处理并返回相应的提示信息给用户。例如,可以在服务端使用Redis等缓存数据库来存储用户的订单信息,一旦发现有重复订单信息,可以及时处理并返回相应的提示信息给用户。设置一个合理的超时时间,在用户提交订单后的一段时间内,如果用户没有得到服务端的响应,可以自动提示用户订单提交超时,让用户重新提交订单。令牌桶算法可以限制用户的请求频率,如果用户的请求频率超过了限制,可以拒绝用户的请求或者提示用户等待一段时间后再进行操作。
如何避免重复下单
tiankongzhouye的博客
05-04 515
系统异常时 666 请求到了,单号更成 666,接着 888 请求到了,单号又更新成 888,但是 666 更新成功的响应丢了,调用方没收到成功响应,自动重试,再次发起 666 请求,单号又被更新成 666了,这数据显然就错了!更新订单服务,通过一个版本号机制,每次更新数据前校验版本号,更新数据同时自增版本号,这样的方式,来解决 ABA 问题,确保更新订单服务的幂等性。实现订单幂等的方法,完全可以套用在其他需要实现幂等的服务中,只需要这个服务操作的数据保存在数据库中,并且有一张带有主键的数据表即可。
C#生成唯一不重复订单
09-03
总结来说,C#中生成唯一不重复订单号可以通过结合日期时间戳和序列号,并使用`lock`关键字来保证线程安全。这种方式简单易懂,但可能需要根据实际业务需求进行优化,例如添加更复杂的序列号生成策略,或者考虑使用...
Java怎么避免重复订单_这个是真的厉害,高并发场景下的订单和库存处理方案,讲的很详细了!...
weixin_39598954的博客
02-27 2097
亿级流量java高并发与网络编程实战99.1元(需用券)去购买 >前言之前一直有小伙伴私信我问我高并发场景下的订单和库存处理方案,我最近也是因为加班的原因比较忙,就一直没来得及回复。今天好不容易闲了下来想了想不如写篇文章把这些都列出来的,让大家都能学习到,说一千道一万都不如满满的干货来的实在,干货都下面了!介绍前提:分布式系统,高并发场景商品A只有100库存,现在有1000或者更多的用户购买...
并发生成重复订单号1
08-08
并发生成重复订单号是一个典型的多线程同步问题,特别是在高并发的电商系统中,确保订单号的唯一性至关重要。以下是对相关知识点的详细说明: 1. **订单号生成策略**: - 订单号通常由日期和序列号组成,如`"yyyy-...
单服务器防止生成重复订单的方法
weixin_33691817的博客
02-16 288
涉及到取餐号的问题,每个商家都有相对应的取餐号,这时候很难用 blockqueue来实现,想了很多办法,首先做测试,生成一堆订单。,然后批量改变订单状态。 class ThreadTest implements Runnable{ private String testString; public ThreadTest(String t...
【浅谈电商】如何防止重复下单
无知而狂妄
10-22 2329
首先我们要知道什么时候是下单操作。以JD为例:购物车 -> 结算页面 -> 下单页面购物车:购物车结算页面:此页面可以查看待支付金额,使用的优惠券,填写地址,运费等等。下单页面:此页面可以选择结算方式,并且页面展示付款倒计时,也就是说订单已经创建完成。在下单页面时,由于用户点击下单按钮多次、或者重试策略导致在订单服务中接收到了两次同样的下单请求。
如何避免重复订单(转)
weixin_33978016的博客
05-27 492
  电子交易的一个很基本的问题,就是避免用户下重复订单。用户明明想买一次,结果一看下了两个单。如果没有及时发现,就会带来额外的物流成本和扯皮。对商家的信誉也不好看。   从技术上看,这是一个分布式一致性问题;但实际上,技术无法100%解决这类问题,得结合多种手段综合处理。这里就来说道说道。 为啥会下重了呢? 原因1:客户端bug   比如下单的按键在点按之后,在没有收到服务器请...
后端怎样防止重复提交订单
LGD_GodV的博客
07-27 602
既然悲观锁有性能问题,为了提升接口性能,我们可以使用。需要在表中增加一个timestamp或者,这里以version字段为例。更新数据的同时version+1,然后判断本次update操作的影响行数,如果大于0,则说明本次更新成功,如果等于0,则说明本次更新没有让数据变更。由于第一次请求version等于1是可以成功的,操作成功后version变成2了。该update操作不会真正更新数据,最终sql的执行结果影响行数是0,因为version已经变成2了,where中的version=1肯定无法满足条件。
服务端如何防止订单重复支付!
JAVA葵花宝典
06-29 184
来源:cnblogs.com/cjsblog/p/14516909.html概述为了防止掉单,这里可以这样处理:为了防止订单重复提交,可以这样处理:附上微信支付最佳实践:概述如图是一个简化...
如何避免订单重复提交
最新发布
08-23
在电商系统中,防止订单重复提交是一个关键任务,主要是为了保护用户的权益,防止重复计费。以下是几种常见的策略: 1. **验证唯一标识**:每个用户下单前,先检查其订单号或者购物车中的商品信息,确保未在短时间内重复提交相同的订单。 2. **锁定表单**:当用户开始填写订单信息时,可以暂时锁定订单表单,防止他们在提交过程中刷新页面或直接复制URL重新提交。 3. **前端校验**:在前端使用JavaScript进行实时验证,例如在提交按钮上添加点击事件,只有在验证所有必填字段都正确无误后才允许提交。 4. **后端校验**:服务器端也需要检查订单是否存在,如果发现相同订单已经存在,应返回错误消息,并阻止再次提交。 5. **设置提交时间窗**:设定一个合理的提交间隔时间,比如用户提交后的一段时间内不允许再次提交新的订单。 6. **数据库事务**:如果有多个并发请求,可以在数据库层面开启事务处理,确保订单的原子性和一致性。 7. **缓存控制**:对于高并发场景,可以利用缓存技术存储订单状态,减少数据库查询,但如果遇到缓存失效或清空,可能会导致重复提交,这时就需要有后端清除缓存机制。 以上策略可以根据实际情况选择组合使用。同时,保持良好的用户提示也是必要的,告知他们为何无法提交重复订单
写文章

热门文章

  • HTTP 304状态码的详细讲解 418270
  • 503 Service Temporarily Unavailable 解决办法-nginx 206617
  • 串口通信的基本知识 97530
  • Js实现将html页面或div生成图片 83172
  • 相关性、平均值、标准差、相关系数、回归线及最小二乘法 80602

分类专栏

  • 元宇宙 4篇
  • C# 234篇
  • Python 8篇
  • asp.net 203篇
  • Javascript 63篇
  • Java 70篇
  • android 16篇
  • html5 17篇
  • web 108篇
  • NodeJs 9篇
  • ionic 25篇
  • MS SQL 52篇
  • MySql 25篇
  • Oracle 2篇
  • 移动互联 35篇
  • 管理类 34篇
  • 转载 203篇
  • 设计模式-架构-重构 32篇
  • 搜索引擎 18篇
  • 数据与性能 49篇
  • linux 27篇
  • SEO 9篇
  • PHP 21篇
  • vc++ 6篇
  • OPC 4篇
  • other 61篇
  • Tools 41篇

最新评论

  • 复制微信公众号图片不能用,防盗链问题

    weixin_38178098: 安卓手机可以正常看到图片,苹果系统没办法正常打开,还是存在防盗链

  • class.getResourceAsStream获取结果为NULL 问题【测试通过】

    晓看云起时: 是这样的兄弟,真难后啊

  • Advanced Installer汉化版教程(打包程序,安装包制作)

    血煞长虹: 请教一下,什么场景,需要用到这个同步

  • Advanced Installer汉化版教程(打包程序,安装包制作)

    血煞长虹: 博主对打包java web工程有研究没。 比如,需要把tomcat+mysql+jdk+elasticSearch+启动bat脚本==>打包为exe 客户拿到exe,直接安装,就可以使用(单机版web应用)

  • IDEA设置System.out.println()和main方法快捷键

    hzc10086: 找不到output怎么办 博主

大家在看

  • 基于STM32的宠物智能胸背带的设计与实现 326
  • 基于python+flask框架的基于微信小程序的新疆特色民宿预定系统(开题+程序+论文) 计算机毕设
  • 基于python+flask框架的基于微信小程序的校园表白墙(开题+程序+论文) 计算机毕设
  • Python函数基础 586
  • JAIN SLEE 中Container Managed Persistent (CMP) 519

最新文章

  • Sqlserver延时执行方法
  • 复制微信公众号图片不能用,防盗链问题
  • 设置多用户同时登录Windows远程桌面
2023年2篇
2022年17篇
2021年28篇
2020年26篇
2019年33篇
2018年27篇
2017年77篇
2016年93篇
2015年79篇
2014年160篇
2013年60篇
2012年39篇
2011年76篇
2010年36篇
2009年75篇
2008年48篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

天下网标王虹口区企业网站优化方案张家口专业的网站优化哪家专业徐州网站优化哪家专业网站seo优化免费渠道有哪些石材行业网站优化比较好性价比高的网站排名优化优势网站eso优化教程雷州seo网站排名优化软件吴江网站优化推广服务事务日志是如何优化网站结构焦作资讯网站搭建优化平凉网站优化推广多少钱天津专业网站优化价格表亳州公司网站优化技巧网站推广优化贵吗鄞州网站优化溧阳市常州网站优化兴义市网站优化营销沁阳网站推广优化费用多少许昌靠谱网站优化公司嘉定区搜索引擎网站优化案例超哥网站建设优化网站优化常见的方法天津优化网站河源网站优化托管案例如何优化网站喜欢易 速达淘宝客网站优化应该怎么做网站排名优化百度价格廊坊网站优化费用宣城网站关键词排名优化香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

天下网标王 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化