使用redis创建有序订单号

       订单号的生成,这是每个交易系统都碰到的问题。方案有很多种,比如uuid、时间戳+随机数、数据库自增长等等。这些方案或多或少都存在一些问题。比如uuid索引性能低下,时间戳+随机数存在可能重复的问题,数据库自增长如果是分布式多表的情况显然是不合适的。更蛋疼的是笔者所在公司业务方提出蛋疼的要求:订单号的格式为yyyymmdd+7位有序数字,比如当天第一笔为yyyymmdd0000001,第二笔就是yyyymmdd0000002,以此类推。公司不怕从订单号看到订单的业务信息,就是这么牛逼,不服?Ok,我们来聊聊当时的解决方案。

1.转变思路
       上文的订单生产方案可以看到有一个共同的特点:在使用时生产!!!我们知道,计算机的任何行为都会有一定资源开销。来分析一下订单号的格式为yyyymmdd+7位有序数字的性能问题:如果是传统的做法,就是查询订单号当日的最大值+1作为当前的订单号,因为查询最大值牵涉到数据库记录排序的问题,这就是一个很大的性能开销,况且如果是多库多表的情况就更糟糕了。
       改变思路,对,改变思路,因为上面所例举的方法都是在创建订单时即时生成的有序订单号,但可以在生成订单之前提前生成订单号,那么就可以减少这部分的开销了。

2.引入redis
       1)创建定时任务,每天凌晨4点生成次日订单号,由于凌晨4点交易量一般不会高,为了减少对主业务的影响故选此时间段。
       2)所有生成的订单号放入一个双向队列里Deque,队列Deque保存在redis的<key,value>结构中,其中key为yyyymmdd+7位有序数字,value为双向队列Deque。
       3)订单系统获取订单号,订单系统从redis中的Deque队列获取首元素作为订单号。由于使用pollFirst()方法,首元素会即时删除,再加上redis是单线程,订单系统基本上不会获取到相同的订单号,即使订单系统是分布式服务也不会有问题。
       4)为了防止出现订单不够用的情况,定时任务系统会定时检测Deque队列的长度,如果订单号过少,在队列Deque尾部追加一定数量的订单号,当然,以当前尾元素为起点进行追加。
       5)为了节省redis内存空间,每天凌晨3点删除保存保存前一天订单号的Deque队列。

定时任务系统、订单系统、redis关系结构图如下:
在这里插入图片描述
       由于牵涉到公司的一些保密协议,代码就不便提供了,请谅解。
总结
       使用redis第三方组件让我们的订单生成得到了几大优化:
       1)杜绝了订单号冲突的问题,以前经常出现这种情况,在同一时间段下单时,查到同一个订单号最大值,产生订单号冲突,导致交易失败,影响用户体验。
       2)减少了数据库消耗。由于订单号的生成在redis上操作完成,和数据库基本没啥关系,因此哪些繁琐的查询查询、恶心的数据库排序通通见鬼去吧。间接也提高了系统性能。
       最后,笔者想多说一句,一个问题可能有多种解决方案,当一个方案有瑕疵时,我们何不换一种思路呢?

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值