生成唯一订单号(16位字符串)

思想: 时间+随机数, 由于订单一般会分库分表, 所以加上用户ID(userId)后两位, 具体怎么加可看具体情况, 理论上时间+随机数+用户ID后两位不能百分百保证唯一, 所以数据库字段还是得建唯一索引保证订单ID的绝对唯一。

规则:

  1. 年份取后两位足矣
  2. 月份取值范围为01-12,所以这里取月份的16进制数(dechex),减少位数
  3. 时分秒,date(‘His’)所表达的结果其实就是000000到235959,而且其中很多数字不会被用到比如126998。一天86400秒,如果从一天的0:0:0算起直到23:59:59使用00000-86400就可以完全表示,这样下来我们就完全可以把date(‘His’)换成五位数字。既然time()函数就是按秒计数,那咱就取time()结果的后五位,同一天之内后五位不会重复出现,比如今天0:0:0后五位是98765,那么到今天23:59:59后五位就应该是98765+86400去掉最高位,相信这个应该是很好理解的
  4. 随机数,秒小数点后取4位
  5. 用户ID(userId)取后两位或取余

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/**
* 随机生成唯一订单号码
*
* @param int $userId
* @return string
* @throws Exception
*/
function createOrderId($userId = 0)
{
if (empty($userId)) {
throw new Exception('用户ID错误, userId=' . $userId);
}
list($ms, $time) = explode(' ', microtime());
$year = date('y', $time); //当前年份,2位数
$month = date('m', $time); //当前月份,2为数,转为16进制只占一位
$day = date('d', $time); //当前日期
return $year . strtoupper(dechex($month)) . $day . substr($time, -5) . substr($ms, 2, 4) . substr($userId, -2);
}
$userId = 110003978;
for ($i = 0; $i < 10; $i++) {
echo createOrderId($userId) . PHP_EOL;
}