订单号、流水号是业务系统的高频需求,要求可读性好、重复率低、便于按时间检索。最朴素的方案就是日期时间加随机数,配合足够长的随机段,碰撞概率在单机场景下可以忽略。
实现思路
前缀加 date 秒级时间保证可读,random_int 生成真随机 6 位数抗碰撞,再拼上毫秒低三位进一步拉开同一秒内的间距;通过 length 参数可统一控制总长度,方便与第三方接口对齐位数。
完整代码
<?php
/**
* 生成业务单号:前缀 + yyyymmddHHMMSS + 6位随机 + 3位毫秒
* @param string $prefix 业务前缀,如 RE 充值 / DD 订单
* @param int $length 单号总长度,超出自动截断
*/
function createOrderNo(string $prefix = "DD", int $length = 32): string
{
$date = date("YmdHis");
$rand = str_pad((string)random_int(0, 999999), 6, "0", STR_PAD_LEFT);
$msec = str_pad((string)((int)(microtime(true) * 1000) % 1000), 3, "0", STR_PAD_LEFT);
$no = $prefix . $date . $rand . $msec;
return substr($no, 0, $length);
}
echo createOrderNo("RE") . PHP_EOL;
// 输出示例:RE20260905103025012345678901
?>防重与扩展
- 同一毫秒内的理论碰撞需两次随机完全相同,概率约百万分之一;
- 要求全局严格唯一的场景,可在此基础上用 Redis INCR 维护每日自增段,如 DD + 日期 + 自增号;
- 写库时对单号字段建唯一索引,极端碰撞时捕获 Duplicate Entry 重新生成一次即可兜底。
小结
该方案零依赖、性能好、可读性强,适合绝大多数业务系统;需要跨机器严格有序时可再叠加分布式 ID 组件。
评论(0)
暂无评论,快来抢沙发吧~