18 位无重复订单号生成代码
这个系列相当于一些小的“工具”,拿来即用,为便捷存在。
思路说明
监听order模型创建事件,在写入数据库之前进行判断,订单号为空时生成18位有效数字编码。订单号的生成规则是8(年月日)+ 6(随机数)+ 4(时间戳后四位)
protected static function boot()
{
parent::boot();
// 监听模型创建事件,在写入数据库之前触发
static::creating(function ($model) {
// 判断订单号字段no是否为空,为空的话调用订单号生成方法
if (!$model->no) {
$model->no = static::findAvailableNo();
// 如果生成失败,就返回false
if (!$model->no) {
return false;
}
}
});
}
public static function findAvailableNo()
{
$prefix = date('Ymd');
for ($i = 0; $i < 18; $i++) {
// 随机生成 6 位的数字,并创建订单号
$no = $prefix.random_int(100000, 999999).substr(microtime(true),-4);
// 判断是否已经存在
if (!static::query()->where('no', $no)->exists()) {
return $no;
}
}
//写入日志
\Log::warning('find order no failed');
return false;
}
个人理解
这个是在实战教程L05的基础上改的。将原来的20位改成了18位,弃用了时分秒,在后一部分使用了毫秒级时间戳的后四位,稍微测试了一下,在我本地环境生成10000条不重复的订单号耗时10s。
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu
for循环的意思是,尝试18次吗
个人认为:
不必杞人忧天的做很多无用的检测,这样反而拖慢了程序的运行效率。
这是我使用的方法(不知道你喜不喜欢)
1、生成规则
8(年月日)+ 6(随机数)+ 4(时间戳后四位)
2、数据库订单字段设唯一索引
3、在执行添加的时候,如果重复,重新执行一次生成规则
理解:毫米后四位+6位随机数基本很少出现重复值了,如果有重新执行方法。
@看上隔壁小花了啦 赞同呀。只要在订单号掺入唯一建就能保证唯一性啦,比如把 order 表的 maxId 放到订单号里
参考一下
snowflake算法,64bit 的。一个 long 的事。这个太依赖系统时间了, findAvailableNo 返回值结构都不唯一?
谨记,批量创建的时候,单号绝对不能用于排序!
查数据库??这样很明显不好吧,我们之前是生成一批到内存中再取
把 for 换成 do...while 会不会好点。
第一种
第二种
年月日时分秒+随机6位 应该就不会重复吧?
snowflake 了解下?
测试了下订单生成带了点,导致微信提示无用订单号