在流量不太高的网站里,如何生成订单号呢,网上肯定也有很多成熟的方案,这里也是提供下自己的思路。
订单号如何生成是要根据当前业务的需求才实现的,所有的东西都是不断进化的,你不可能起步就按照京东淘宝的标准来,根据实际情况实际分析就可以了,脱离需求谈实现都是耍流氓。下面也仅仅是对交易量不高的网站提供的一点思路。
20220310 新增 #
以前没有高并发的经验(其实现在也没有),随手写了点订单号生成的逻辑。不过逻辑确实有问题,任何依赖随机数的订单号系统,都是耍流氓。
既然是随机数,就有可能产生冲突;依赖时间的,就得考虑时钟回拨的问题;分布式的,就得考虑多台机器之间订单号的互斥性;有自增类型的,就得考虑怎么维护这个自增的数字,是统一在 redis 中维护,还是在某个时间段内自增,等等。
高并发下,生成订单号的特点是:
- 唯一性;
- 不可推测性;
- 效率高;
现在有很多经过大厂验证过的方案,如雪花算法、UUID、数据库自增、Redis、美团 Leaf 等,都是经得起考验的订单号生成算法。
在要求不高的场景下,如不限制订单号的长度、没有分布式、不考虑时钟回拨等,那么时间戳 + (自增 | 随机数)
就足够了。
如 jQuery 中的 jsonp 的 callback 名称,就是时间戳 + 随机数的方式生成的。每个客户端都是独立的,也不用考虑多个客户端冲突的问题。
其次是时间戳 + 自增的方式,这个自增可以限制在单位时间内自增,时间戳一改变,则自增数字重置。
const create = () => {
let lasttime = ''; // 上一个时间戳
let num = 0; // 自增的数字
return () => {
const now = Date.now().toString(36);
if (now === lasttime) {
// 若当前时间戳与刚才相同,则直接自增
num++;
const inc = `0${num.toString(36)}`.slice(-2);
return `${now}${inc}`;
}
// 若当前时间戳发生变化,则自增数字重置
lasttime = now;
num = 0;
return `${now}00`;
};
};
const uuid = create();
// 使用:
for (let i = 0; i < 1000; i++) {
console.log(uuid()); // l0kd0nep1w
}
原文 #
思路:
- 日期+自增数字 : ,如果你的网站每天的交易量很小,那么使用
日期+自增数字
的方式就完全足够使用了; - 日期+随机数 : 如果自增数字会暴露每天的交易量,那么日期+随机数也是一种比较好的方式。但是每次生成随机数后,都要检测当前随机数是否已经使用,如果已经使用还需要重新生成;
下面的这种方式是我目前在使用的,生成的订单号也会比较长,订单号由三部分组成:
- 秒级的时间,当然你也可以使用毫秒级的时间;
- 随机数+uid 的后 6 位: (md5(毫秒级级时间戳)+uid)的后 6 位;
- 1000-9999 之间的随机数
最终生成的订单号是这样的: 2016120108580747d4d10790 。 20161201085807 是精确到秒级的时间,47d4d1 是 md5+uid,0790 是随机数。这样的一种订单号生成规则,在并发量不太高的情况下时:
- 多个用户几乎同时提交订单时,不会造成生成重复的订单号,因为每个订单号都是与 uid 相关联的;
- 同一个用户若一秒内提交的订单不多的话,第 2 步和第 3 步也是能满足订单号生成的,不过会有一定的风险。
不过这种订单号生成方式会暴露用户的 uid,我们可以使用某些转换方式,将 uid 隐藏。
这也是我提供的一种思路而已,欢迎大家参考。