2019年7月2日16:43:41
订单号设计,这个功能说复杂也复杂,简单也简单
先说一下比较基础的做法,
例如
$orderKey = uniqid(date('Ymd')); pp($orderKey);
201907205d32de71e6002
利用php自带的生成唯一ID 方法,生成带日期的唯一订单号,并发情况下不会重复,经过测试过,连续写10000次不会重复
请不要使用随机数函数,因为会重复
设计思路的话有几种:
1,有意义的位数的订单号
日期+订单来源+支付类型+业务标记+用户ID+自递增数
这样就比较一目了然,也是很常见的 设计方案
2,可以反解的订单号,本身一眼是看不出你订单的意义
可以通过反解订单知道此订单的情况,这不是和方案1一样吗?方案一会暴露系统的订单设计意义,方案可能会涉及到加密等问题,为了数据安全考虑
3,无意义的订单号为了处理并发,有些情况下,为了巨大的并发量会设计一个算法来生产订单号的接口,直接使用
4,使用redis,mysql锁机制做自增数,一个内部调用的一个服务这样然后可以配合任意的前缀
使用mysql做计数器的一个demo
public static function counter($shop_id = 0, $type = null, $need_transaction = 1, $pad_length = 15, $now = null) { if (empty($type)) { throw new Exception('type标签不能为空'); } if (empty($now)) { $now = time(); } /* * 合同生产需要短一点,根据20190703XXXX的格式,长度为12,再短的话,就会出现一天之内生产333个,可能后期业务会不够用 */ if ($type == 5) { $time = date('Ymd', $now); $pad_length = 11; } else { $time = date('Ym', $now); } $length = $pad_length - mb_strlen($time); $tag = self::counter_array($type); $name = $time . '_' . $tag; $need_transaction == 1 && DB::beginTransaction(); try { $Counter = Counter::where('name', $name)->first(['value', 'id']); if (empty($Counter)) { //没有就插入 $Counter = new Counter; $Counter->name = $name; $Counter->type = $type; $Counter->tag = $tag; // $Counter->shop_id = $shop_id; $Counter->save(); $Counter = Counter::where('name', $name)->first(['value', 'id']); } $Counter = $Counter->toArray(); //加锁 防止生成的订单号出错,没有在name上加索引 Counter::where('id', $Counter['id'])->lockForUpdate()->first(); $new_count = (float) $Counter['value'] + 3; Counter::where('name', $name)->update(['value' => $new_count]); $string = $time . str_pad($new_count, $length, '0', STR_PAD_LEFT); $need_transaction == 1 && DB::commit(); return $string; } catch (Exception $e) { $need_transaction == 1 && DB::rollBack(); throw new Exception($e->getMessage()); } }
//订单计数器映射数组 public static function counter_array($type = null) { $array['5'] = 'contract'; $array['10'] = 'sales_order_number'; $array['20'] = 'purchase_order_number'; $array['30'] = 'logistics_order_number'; $array['40'] = 'inbound_order_number'; $array['50'] = 'outbound_order_number'; $array['60'] = 'purchase_point_number'; $array['70'] = 'express_number'; $array['75'] = 'return_express_number'; $array['80'] = 'sale_voucher_number'; $array['90'] = 'batch_number'; $array['100'] = 'purchase_settle_number'; $array['110'] = 'sales_settle_number'; $array['120'] = 'sales_point_number'; $array['130'] = 'k3_pay_number'; if (empty($type)) { return $array; } return $array[$type]; }