Wenzi

小型网站如何生成订单号

蚊子前端博客
发布于 2016/12/05 00:00
在流量不太高的网站里,如何生成订单号呢,网上肯定也有很多成熟的方案,这里也是提供下自己的思路

在流量不太高的网站里,如何生成订单号呢,网上肯定也有很多成熟的方案,这里也是提供下自己的思路。

订单号如何生成是要根据当前业务的需求才实现的,所有的东西都是不断进化的,你不可能起步就按照京东淘宝的标准来,根据实际情况实际分析就可以了,脱离需求谈实现都是耍流氓。下面也仅仅是对交易量不高的网站提供的一点思路。

20220310 新增 #

以前没有高并发的经验(其实现在也没有),随手写了点订单号生成的逻辑。不过逻辑确实有问题,任何依赖随机数的订单号系统,都是耍流氓。

既然是随机数,就有可能产生冲突;依赖时间的,就得考虑时钟回拨的问题;分布式的,就得考虑多台机器之间订单号的互斥性;有自增类型的,就得考虑怎么维护这个自增的数字,是统一在 redis 中维护,还是在某个时间段内自增,等等。

高并发下,生成订单号的特点是:

  1. 唯一性;
  2. 不可推测性;
  3. 效率高;

现在有很多经过大厂验证过的方案,如雪花算法、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
}

原文 #

思路:

  1. 日期+自增数字 : ,如果你的网站每天的交易量很小,那么使用日期+自增数字的方式就完全足够使用了;
  2. 日期+随机数 : 如果自增数字会暴露每天的交易量,那么日期+随机数也是一种比较好的方式。但是每次生成随机数后,都要检测当前随机数是否已经使用,如果已经使用还需要重新生成;

下面的这种方式是我目前在使用的,生成的订单号也会比较长,订单号由三部分组成:

  1. 秒级的时间,当然你也可以使用毫秒级的时间;
  2. 随机数+uid 的后 6 位: (md5(毫秒级级时间戳)+uid)的后 6 位;
  3. 1000-9999 之间的随机数

最终生成的订单号是这样的: 2016120108580747d4d10790 。 20161201085807 是精确到秒级的时间,47d4d1 是 md5+uid,0790 是随机数。这样的一种订单号生成规则,在并发量不太高的情况下时:

  • 多个用户几乎同时提交订单时,不会造成生成重复的订单号,因为每个订单号都是与 uid 相关联的;
  • 同一个用户若一秒内提交的订单不多的话,第 2 步和第 3 步也是能满足订单号生成的,不过会有一定的风险。

不过这种订单号生成方式会暴露用户的 uid,我们可以使用某些转换方式,将 uid 隐藏。

这也是我提供的一种思路而已,欢迎大家参考。

标签:ordern
阅读(803)
Simple Empty
No data