工作中的点点滴滴-订单号的创建方式

  当我们在考虑生成订单号的同时,我们也要考虑一下这么几个问题:第一,如何让你的订单号是趋势递增的,但是却有不是严格递增?第二,如何保证订单号的长度一致(考虑到数据库索引的优化,这里要是整数),第三个就是在并发的场景下如何保证正确性?

  第一个问题,因为现在的系统都是基于分布式微服务的,因此生成订单号组件应该是独立于系统之外的,可以复用的。如果重复造轮子,首先,会浪费人力物力,其次,不同层次开发人员,设计思路不同,从而导致组件集中管理困难复杂。因此在多个系统同时使用一个订单号生成器组件时,出现订单号趋势递增是可能的。但是另外一个问题假如订单号是严格趋势递增的,那么可以在凌晨12点整点下一个订单,得到今天所有订单的第一个订单号,然后在23点59分再下一个订单,得到今天最后一个订单号,将这个订单号相减,就能得到平台一天的订单总数量。想想你的竞争对手每天都知道你买了多少件商品,而你却对其一无所知,非常可怕。第二个问题,订单号的作用就是便于查询。一般正常使用场景应该是订单出现异状时候,用户将订单号报给客服,当客服在返回给我们后台的时候,处理定位也会非常的方便,l另外常见关系型数据库的存储引擎支持整型类型的索引非常友好,相对字符串,有天然的优势。订单号,当我们使用了一些特殊含义的数字组成比如系统时间+俩位随机数+渠道id这样的,从而也就长度固定了。这样在后面可能出现的正对订单数据的分析也会更方便一些。第三个问题,就是用来解决我们前面正在遇到的问题的,如何高效率的来。

  首先是采用UUID,这种方式也是在从业过程中遇到的适用最多的方式,总的来说,UUID码由以下三部分组成:[1] 当前日期和时间。[2] 时钟序列。[3] 全局唯一的IEEE机器识别码(如何有网卡,从网卡获得,没有网卡则以其他方式获得)。在JDK1.5引入了UUID这个工具类,方便开发人员得到UUID码,提供了静态API:randomUUID,一般我们都会有一个uuid的工具类:

1 public class UUIDUtils {
2     public UUIDUtils() {
3     }
4 
5     public static String getId() {
6         String id = UUID.randomUUID().toString().replace("-", "");
7         return id;
8     }
9 }

由于UUID获取使用简单、不依赖其他组件(JDK支持)、不影响数据库的扩展,因此在单体应用中得到了大量的使用。但是最大的不足就是太长(32位字符串,空间占用大、对用户不友好)、不好索引(DB对整型数据的索引支持非常友好,而字符串则一般),在集群环境下,重复几率大。所以UUID总结下来最大的亮点就是“获取简单,使用简单”,单体应用非常推荐。但是呢可读性差、长度不友好、无序、无缘大型电商系统。

  然后是第二种:数据库自增,在单体应用中也使用得非常广泛,甚至在某些小型稳定的集群DB中也能看见数据库自增的身影。数据库自增的原理就是靠两个变量:起始位和偏移量。由于自增库表需要在前期对偏移量、起始位做好规划,扩展起来比较麻烦,而且不能做水平分表,否则插入删除易出现问题,自增依赖mysql内部维护“自增锁”,高并发插入性能低。在业务操作父子表时,要“先父后子”。

  第三种就是使用redis的自增,:利用增长计数API(incr),业务系统在自增长的基础上,配合其他信息组装成一个唯一ID,在使用比较简单, 扩展性强,方便结合业务进行处理,redis是单线程的,保证并发不会出现重复。不足也就是非常明显,首先就是 引入带三方依赖和库,并且每获取一次ID增加一次网络开销, reids需要高可用,增加了成本。

 

posted @ 2021-01-26 10:54  小杨ABC  阅读(264)  评论(0编辑  收藏  举报