2019年7月2日16:43:41php
訂單號設計,這個功能說複雜也複雜,簡單也簡單mysql
先說一下比較基礎的作法,redis
例如算法
$orderKey = uniqid(date('Ymd')); pp($orderKey);
201907205d32de71e6002
利用php自帶的生成惟一ID 方法,生成帶日期的惟一訂單號,併發狀況下不會重複,通過測試過,連續寫10000次不會重複sql
請不要使用隨機數函數,由於會重複express
設計思路的話有幾種:數組
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]; }