如何防止订单重复提交以及如何防止订单重复确认

订单重复问题已经是老生常谈的问题了,我们熟悉的淘宝购物流程,购物车-->生成订单--》提交订单--》订单确认--》支付订单--》备货--》发货,这里可能会有一些问题,例如,有人恶意或者无意的重复提交订单,从而导致数据库保存的订单数量与实际不符,重复提交订单导致用户体验不佳,甚至更为严重的是,用户重复支付了同一个订单。所以,涉及到订单,应该首先想清楚如何设计才能保证系统不会出现这些问题

如何防止订单重复提交

首先说两个我们购物时经常有过的体验或者说购物网站的网页提醒

  • 你提交的动作过快,请稍后尝试
  • 你的订单已经超时,请刷新页面后重新提交
    看到这些提示,说明该购物网站做了订单提交的限制,一方面是防止有人恶意无限制提交订单,所以限制了一定时间内最大可操作次数,另一方面是为了保证订单无重复提交。那么这是怎么做到的呢?
    第一个应该比较简单,限制某个时间内的最大操作次数只需要有一个计数器就可以,计数器可以用redis实现,设置一个带有有效时间的值作为计数器,如果值不存在则自动创建,超过某一个值就认为操作次数用完即可以实现。
    第二个可以使用token机制,token即令牌,学过spring security的相信对这个词不会陌生。我们可以使用类似spring security的机制在页面上生成一个token,当提交订单时,根据该token的有效时间和允许的使用次数来判断订单是否允许提交,从而规避重复提交的问题。当然,有人会问,在高并发的情况下,如果是判断token有效之前有很多同一个用户的提交线程过来(用户正常使用一般不会出现这种情况,一般是压力测试工具导致的),那么还是会重复提交,所以,这里需要用到锁机制,访问同一个用户的token同一时间只能有一个线程,token使用之后失效了就会被清掉,之后的线程就找不到该token,从而认为订单不能提交。

订单确认支付

如支付宝和微信等,支付宝和微信本身是怎么限制订单只能支付一次的呢?订单怎么保证只会被支付一次呢?这个问题相对来说就简单很多了,同一订单的状态更新的SQL只需要带上条件,利用的是数据库的行锁。当然,如果是分布式系统,这里涉及到的问题会更多。

update table item set item.status=:newstatus where item.id = :id and item.status = oldstatus.

对比案例

  • 美团GTIS
    主要看GTIS的流程图以及想想其交易ID的作用,交易之前,后台会返回一个交易ID给前端,前端在点击交易按钮时需将该交易ID和其他交易信息同时返回给后台进行处理,通过全局的交易ID实现“该次交易的”幂等性
    美团GTIS.png

参考资料和研究

  • 分布式锁的对比分析:非常好的一篇文章,包含下面的关键词:可重入、阻塞、公平、排他、乐观、悲观、单点、死锁发生、连接池状况、实现种类、实现方式
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,312评论 19 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,039评论 25 709
  • 小白一枚,很想丰富自己的业余生活,也喜欢画画。 听了老师的课才明白了一些专业知识,不过幸亏老师讲的精简又细致。 懂...
    荔枝不怕甜阅读 1,924评论 1 1
  • 江山如画势如鸿 日月乾坤两袖中 登高一呼山河动 天兵鬼将莫不从
    王梓丹青阅读 1,475评论 4 2
  • 北方honey阅读 1,079评论 0 0