尝试解析电商网站订单号的生成方式

订单是整个电商网站的核心,整个电商的流程也是围绕订单的状态执行的,本文尝试向大家介绍订单号的生成方式。

电商下单途径

现在大型电商网站大多都有好几种下单途径,比如:通过Web网站下单,通过打电话到呼叫中心下单(CallCenter),使用手机APP下单。

如果只采用单数据库来存储订单信息的话,随着订单量的增加,单数据库写压力必然增大,数据库服务器就会不堪重负,所以大都会根据业务采用分库做法,比如:

Web下单调用生成订单API后,存储在Web订单库;
CallCenter下单调用生成订单API后,存储在CallCente订单库;
APP/WAP下单调用订单生成API后,存储在Wap订单库。

最后需要以上各自的订单数据库同步到后台订单主库中,后台订单主库是我们的核心库,存储所有订单数据。

电商网站中订单表大多都是以订单号做表的主键,我们必须保证各个子订单库中存储的订单号不能重复,这样才能保证可以安全的同步到后台主库中。

电商订单号规则

目前几个大型电商网站是如何生成订单号的,我们还是先看看他们的订单规则吧:

京东商城订单号格式:157444499
苏宁易购订单号格式:2000839647
凡客诚品订单号格式:213052230059            分解:2-13-0522-30059
银泰网订单号格式:10030522161715            分解:1-00-3-0522-161715

凡客诚品和银泰网的订单号生成规则

初看一下,凡客诚品和银泰网订单号都含有0522,这是因为这2张订单都是2013年5月22号下的订单。我们总结一下:

凡客的订单号规则:下单渠道编码+年份的后2位+月+日+订单数

银泰的订单号规则:年份的第三位数+下单渠道编码+年的后1位+月+日+订单数

实现方式应该是在数据库中新建一张订单量记录表维护每天的订单量。

生成订单时,根据当天的日期查询这张表的订单数量加1,然后组合下单渠道编码(比如下单渠道编码Web=1,CallCenter=2, Wap=3)即为订单号,生成订单成功后在回写数据库(需记录订单量)。

弊端:这种方式在高并发下会频繁更新订单量记录表,很容易产生锁表。

京东商城和苏宁易购的订单号看不出规则

我们猜想应该是有一个全局数据库,这个数据库中只有一张订单表(Order),表Order只有一个自增的字段Id,这个自增的字段Id就是订单号。

所有生成订单的API会首先访问全局数据库的Order表获得订单号,然后再生成订单,这样就可以保证子库订单号不重复。

此实现方式避免了频繁的更新操作,只有Insert操作,性能要好很多。

接下来再来看个案例。

小米网订单号详解

订单号的作用:唯一性、标识性。

示例:12月18日 0:53:54 下单,订单号如下:

1—111218—03234—5170

分段分析一下:

A、第一部分估计为机型:如1表示米1,2表示米2。

另一种理解:1表示订单的类别,1是购买的单,2是退换货的单。

B、第二部分为年月日,均取两位;

C、第三部分为秒,将下单的时分秒转化为多少秒,就可以推算出下单时间,本示例是0:53:54下单的,这里最大值是86400;

D、第三部分估计为累计,总数9999,到满了又从0开始,从而保证订单号肯定是唯一性的。也就是说,小米认为在同一秒钟内,不可能超过1W张单,从这也基本得出“订单号里是看不出你下单的排在第几位”。

订单命名的几种规则

1、不重复

这点我相信大家都懂,订单的唯一性不用解释。

2、安全性

你的订单编号不能透露你公司的真实运营信息,比如你的订单就是流水号的话,那么别人就可以从订单号推测出你公司的整体运营概括了。所以订单编码必须是除了你们公司少部分人外,其他人基本看不懂的。参考京东和淘宝的编码规则,基本别人是搞不清是什么意思的。

其实最好的防泄漏编码规则就是在编码中不要加入任何和公司运营的数据。

3、不能使用大规模随机码

很多人分析订单编码规则的时候,第一个念头肯定是不重复唯一性,那么第二个念头可能就是安全性,那么同时满足前两者的第三个念头就是随机码了。因为大规模的随机码随机生成,因为本身就没有意义所以无所谓泄密了。但是事实上这种编码规则在实现上会有很大问题的。

随机码满足第二点安全性要求,为了满足第一点不重复特性,那就得在生成随机码的时候对比历史数据是否有重复,如果你的订单数量到达了十万次,你每次生成订单编码时就得对比十万条历史数据,你可想而知会造成什么巨大问题。

但是难道随机码就不能在编码中使用了吗?小规模的随机码是可以使用的,比如2~3位,这种随机码一般都是和流水号等结合使用,主要作用是为了隐藏流水号的真实数据而进行使用的。

据实际测试估算了生成随机码并且检测重复所花费的时间在纳秒级别。但是我还是保持原来观点,觉得这种生成规则存在方向性问题,可能会造成检测时间过长的问题出现。

4、防止并发

这条规则主要针对编码中有时间的设定。

5、控制位数

这点很好理解,订单号的作用就是便于查询。

一般正常使用场景应该是订单出异状或者退货的时候,用户将订单号报给客服,由客服进行查询,所以一般在10~15位为好,如京东10位,淘宝15位。

几种编码规则

1、年月日时分秒+用户ID

命名用户ID时要注意,不要用流水号。可以采用区域ID+随机码+流水号+随机码方式。

解析一下:

1、唯一性:时间是单向的,确保唯一性;
2、安全性:确保用户ID安全即可;
3、随机码不参与判断,因为之前数据已确保无重复;
4、在同1秒钟,同一用户是不会产生2个订单编码的,所以可以防并发;
5、位数可能会在20位之内,位数比较多。

2、年月日时分秒微秒+随机码(2)+流水号+随机码(3)

解析一下:

1、唯一性:时间是单向的,确保唯一性;
2、安全性:确保流水号不会识别出即可;
3、随机码的位数和前后都是保密的,所以如果不清楚这一点的话,是很难判断出流水号的位数的。因为同时产生的订单数量很多,编码不具备线性对比功能。就算知道了流水号,可以在初始化时进行赋值;
4、在同1秒钟,同一用户是不会产生2个订单编码的,所以可以防并发;
5、位数可能会在20位之内,位数比较多。

(以上来自知乎@benben)

订单号常见的几种方式

1、利用数据库主键值产生一个自增长的订单号(订单号即数据表的主键)

2、日期+自增长数字的订单号(比如:2012040110235662)

3、产生随机的订单号 (65865325365966)

4、字母+数字字符串式,字母可包含特别意义 (C02356652)

订单号设计原则:按需设计

用来检索订单详细信息的唯一特征码,可以利用订单号检索到下单日期、产品类别、颜色、尺码(或款式)、仓位等信息,订单号包含过多的信息有点“画蛇添足”的意味!只要按需设计即可!

订单号设计用户体验规则

1、订单号无重复性;

2、如果方便客服的话,最好是“日期+自增数”样式的订单号,客服一看便知道订单是否在退货保障期限内容;

3、订单号长度尽量保持短(10位以内),方便用户,尤其电话投诉时,长的号码报错几率高,影响客服效率;

4、订单号尽量保持数字型(纯整数),在数据库订单索引查询中,长整数字型的数据索引与检索效率,远远高于文本型,因此尽量避免“字母+数字字符串式”!

(以上来自知乎@LO)

一个网友的实操案例

前阵子,公司有个电子商务项目,需要生成订单号。

当时的考虑很简单,取系统时间加上随机数,或者使用 uniqid() 方法。

我们都知道,订单号最基本的要求就是唯一,这个条件必须满足。仔细考虑下上述方法,在顾客购买量少的情况下,订单重复的可能性为零,但是在购买高蜂期生成的订单号重复是很有可能发生的。所以上述方法不可靠,有待强化。

在网上找了一番,发现这位同学的想法挺不错的,redtamo,具体的请移步过去看看,我作简要概述,该方法用上了英文字母、年月日、Unix 时间戳和微秒数、随机数,重复的可能性大大降低,还是很不错的。使用字母很有代表性,一个字母对应一个年份,总共16位,不多也不少,呵呵。

<?php 
$yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
$orderSn = $yCode[intval(date('Y')) - 2011] . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
?>

生成效果:

A422694333616096

话说,最后项目并没有使用这种方法,说是没必要搞这么复杂!!不用也没关系,我就写个笔记,以后备用。

以上内容有点乱,大家慢慢吸收!