溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么正確設(shè)計(jì)一個(gè)訂單號(hào)

發(fā)布時(shí)間:2021-10-19 09:58:12 來(lái)源:億速云 閱讀:242 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“怎么正確設(shè)計(jì)一個(gè)訂單號(hào)”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

訂單號(hào)定義

我們經(jīng)常提及到的訂單號(hào),大多數(shù)是在電商購(gòu)物場(chǎng)景下的一個(gè)唯一標(biāo)識(shí)字符串。實(shí)則訂單號(hào)并不僅僅指的是電商系統(tǒng),只要需要這樣的業(yè)務(wù)場(chǎng)景,我們都可以使用訂單號(hào)的模式來(lái)處理。例如我們的省份證號(hào),要求唯一可讀性強(qiáng)等特點(diǎn),也可以將之理解為一個(gè)訂單號(hào)。 

訂單號(hào)規(guī)則

1.不重復(fù)。不管你的訂單號(hào)設(shè)計(jì)的是多復(fù)雜還是多簡(jiǎn)單,首先我們需要確保的是訂單號(hào)在一個(gè)系統(tǒng)中是唯一的。

2.安全性。訂單號(hào)需要做到不容易被人為的猜測(cè)或者推測(cè)出來(lái)。例如訂單號(hào)包含系統(tǒng)的流水信息,用戶信息等保密相關(guān)的信息。

3.禁用隨機(jī)碼。隨機(jī)碼從一定程度來(lái)說(shuō),更安全、不重復(fù)性更高,但是可讀性差。例如生成類似這樣的隨機(jī)碼(sdfsad12312sfsdf201),不管是從系統(tǒng)角度還是從人為角度去讀取,完全沒(méi)法直接辨別。

4.防止并發(fā)。針對(duì)系統(tǒng)的并發(fā)業(yè)務(wù)場(chǎng)景(如秒殺),一定需要做到并發(fā)場(chǎng)景下,訂單編號(hào)生成快速、不重復(fù)等要求。

5.控制位數(shù)。訂單號(hào)的位數(shù)盡量在 10 位-20 位之間。太短的情況下,如果交易量過(guò)大,很難做到防止重復(fù),太長(zhǎng)可讀性差、意義也不大。

6.盡量使用數(shù)字。從軟件角度,數(shù)字存儲(chǔ)的訂單號(hào),占用空間小、檢索快。 

淘寶規(guī)則

怎么正確設(shè)計(jì)一個(gè)訂單號(hào)   

上面的截圖,是個(gè)人在淘寶上面進(jìn)行充值的訂單編號(hào),這里只截取了幾個(gè)。在實(shí)際的過(guò)程中,發(fā)現(xiàn)所有訂單號(hào)都有一個(gè)相似的特點(diǎn)(紅色框出來(lái)的地方)。個(gè)人猜測(cè),這應(yīng)該是和買家相關(guān)的信息,例如買家的 ID 編號(hào)情況。

下面的的幾個(gè)規(guī)則,是淘寶訂單編號(hào)生成的規(guī)則(只具備參考意義,與實(shí)際存在差距)。

1.總共 18 位。

2.前 14 位為序號(hào)。

3.15-16 位賣家 ID 的倒數(shù) 1-2 位。。

4.17-18 位買家 ID 的倒數(shù) 3-4 位。

上面的幾個(gè)規(guī)則具備一定的參考意義。從第 3 和 4 點(diǎn),我們不難分析出來(lái),通過(guò)這樣的方式來(lái)實(shí)現(xiàn)訂單號(hào),在一定程度很難出現(xiàn)重復(fù)的訂單編號(hào)。那是為什么呢?

1.賣家的 ID 和買家 ID 的都是在下單之前生成的,具備唯一性。因?yàn)檫@兩個(gè) ID 事先生成,即使出現(xiàn)并發(fā)場(chǎng)景,通過(guò)這兩組的唯一標(biāo)識(shí)就很難生成重復(fù)的單號(hào)。

2.很大程度上滿足了一些并發(fā)高的業(yè)務(wù)場(chǎng)景下,單號(hào)重復(fù)的情況。或許你會(huì)考慮像雙十一這樣的場(chǎng)景下,實(shí)則絕大部分系統(tǒng)都無(wú)法達(dá)到這樣的業(yè)務(wù)場(chǎng)景。

 

生成方式

前面提到了生成的規(guī)則,那要實(shí)現(xiàn)這樣的規(guī)則,該如何實(shí)現(xiàn)會(huì)比較好呢?下面總結(jié)幾種常見(jiàn)的處理方式。怎么正確設(shè)計(jì)一個(gè)訂單號(hào)

 
UUID

UUID 是 Universally Unique Indentifier 的縮寫,翻譯為通用唯一識(shí)別碼,顧名思義 UUID 是一個(gè)用于唯一標(biāo)識(shí)一條數(shù)據(jù)、記錄的,其按照開(kāi)放軟件基金會(huì)(OSF)指定的標(biāo)準(zhǔn)進(jìn)行計(jì)算,用到了以太網(wǎng)卡地址(MAC)、納秒級(jí)時(shí)間、芯片 ID 碼和許多可能的數(shù)字。

總的來(lái)說(shuō),UUID 碼由以下三部分組成:

1.當(dāng)前日期和時(shí)間。

2.時(shí)鐘序列。

3.全局唯一的 IEEE 機(jī)器識(shí)別碼(如何有網(wǎng)卡,從網(wǎng)卡獲得,沒(méi)有網(wǎng)卡則以其他方式獲得)。

UUID 的標(biāo)準(zhǔn)形式包含 32 個(gè) 16 進(jìn)制數(shù)字,以連字號(hào)分為五段,形式為 8-4-4-4-12 的 32 個(gè)字符。示例:550e8400-e29b-41d4-a716-446655440000。關(guān)于 UUID 的更多介紹,可以參考該文章

 
雪花算法

Snowflake 是 Twitter 內(nèi)部的一個(gè) ID 生算法,可以通過(guò)一些簡(jiǎn)單的規(guī)則保證在大規(guī)模分布式情況下生成唯一的 ID 號(hào)碼。其組成為:怎么正確設(shè)計(jì)一個(gè)訂單號(hào)

第一個(gè) bit 為未使用的符號(hào)位。

第二部分由 41 位的時(shí)間戳(毫秒)構(gòu)成,它的取值是當(dāng)前時(shí)間相對(duì)于某一時(shí)間的偏移量。

第三部分和第四部分的 5 個(gè) bit 位表示數(shù)據(jù)中心和機(jī)器 ID,其能表示的最大值為 2^5 -1 = 31。

最后部分由 12 個(gè) bit 組成,其表示每個(gè)工作節(jié)點(diǎn)每毫秒生成的序列號(hào) ID,同一毫秒內(nèi)最多可生成 2^12 -1 即 4095 個(gè) ID。

需要注意的是:

在分布式環(huán)境中,5 個(gè) bit 位的 datacenter 和 worker 表示最多能部署 31 個(gè)數(shù)據(jù)中心,每個(gè)數(shù)據(jù)中心最多可部署 31 臺(tái)節(jié)點(diǎn)。

41 位的二進(jìn)制長(zhǎng)度最多能表示 2^41 -1 毫秒即 69 年,所以雪花算法最多能正常使用 69 年,為了能最大限度的使用該算法,你應(yīng)該為其指定一個(gè)開(kāi)始時(shí)間。

 
數(shù)據(jù)庫(kù)自增

在數(shù)據(jù)庫(kù)中可以通過(guò)給訂單列設(shè)置為自增列,并且給該列設(shè)置一個(gè)初始值。這樣通過(guò)數(shù)據(jù)庫(kù)實(shí)現(xiàn)訂單的自增、無(wú)重復(fù)情況。但通過(guò)數(shù)據(jù)庫(kù)實(shí)現(xiàn)并發(fā)能力低,單表存在只能有一個(gè)自增列的情況,后期對(duì)數(shù)據(jù)的分表處理也不夠友好。

 
分布式組件

通過(guò)分布式組件的方式,我們也可以實(shí)現(xiàn)訂單號(hào)的處理。例如使用 Redis 作為分布式組件。通過(guò) Redis 的隊(duì)列、incr 等功能來(lái)實(shí)現(xiàn)。怎么正確設(shè)計(jì)一個(gè)訂單號(hào)

 

實(shí)例演示

 
UUID 方式
// 生成方式一
function uuid($prefix = '') {
  $chars = md5(uniqid(mt_rand(), true));
  $uuid  = substr($chars,0,8) . '-';
  $uuid .= substr($chars,8,4) . '-';
  $uuid .= substr($chars,12,4) . '-';
  $uuid .= substr($chars,16,4) . '-';
  $uuid .= substr($chars,20,12);
  return $prefix . $uuid;
}
echo uuid();
// output
// b2fa188c-23a8-d1b6-432d-649db4eb34c7

// 生成方式二(利用Linux內(nèi)部生成的uuid)
echo exec("cat /proc/sys/kernel/random/uuid");
// output
// b2792783-7c9f-43d0-8d31-38411e17fc2f

// 生成方式三
function uniqidReal($lenght = 13) {
  if (function_exists("random_bytes")) {
      try {
          $bytes = random_bytes(ceil($lenght / 2));
      } catch (Exception $e) {
      }
  } elseif (function_exists("openssl_random_pseudo_bytes")) {
      $bytes = openssl_random_pseudo_bytes(ceil($lenght / 2));
  } else {
      throw new Exception("no cryptographically secure random function available");
  }
  return substr(bin2hex($bytes), 0, $lenght);
}

echo uniqidReal();
// output
// 9f39aa0ecd89d
   
雪花算法
require_once __DIR__.'/vendor/autoload.php';

$snowflake = new \Godruoyi\Snowflake\Snowflake;
echo $snowflake->id();
// output
// 199778615951360000

// 更多高級(jí)用法及實(shí)現(xiàn)原理參考原倉(cāng)庫(kù):https://github.com/godruoyi/php-snowflake/blob/master/README-zh_CN.md
   
Redis 實(shí)現(xiàn)
// 連接Redis
$redis = new \Redis();
$redis->connect('192.168.0.112', 6379);
$cacheKey = date('Y:m:d');
$initVal  = 10000;
// 實(shí)現(xiàn)方式一(使用隊(duì)列)
for ($i = 0; $i < 10; $i++) {
    $redis->lPush($cacheKey, $initVal + $i);
}
$redis->rPop($cacheKey);
// 實(shí)現(xiàn)方式二(使用incr)
if ($redis->get($cacheKey)) {
    // 返回新增后的值
    return $redis->incr($cacheKey);
} else {
    // 設(shè)置一個(gè)默認(rèn)的初始值
    $redis->set($cacheKey, $initVal);
    return $cacheKey;
}
   
數(shù)據(jù)庫(kù)實(shí)現(xiàn)

數(shù)據(jù)庫(kù)直接就不演示,直接通過(guò)設(shè)置表字段屬性就行。主要設(shè)置字段值的初始值、偏移量。

mysql root@127.0.0.1:(none)> show variables like '%auto_incr%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 1     |
| auto_increment_offset    | 1     |
+--------------------------+-------+
2 rows in set
Time: 0.012s
   

總計(jì)與分析

通過(guò)上面的示例演示,下面針對(duì)這幾種情況做一個(gè)分析與總結(jié)。盡可能的選擇一種合理的方式。

實(shí)現(xiàn)方案優(yōu)勢(shì)劣勢(shì)
UUID實(shí)現(xiàn)簡(jiǎn)單、方便;重復(fù)性低;數(shù)據(jù)庫(kù)查詢效率低可讀性低;過(guò)于冗長(zhǎng)
雪花算法基于內(nèi)存、速度快;性能高;不會(huì)產(chǎn)生額外的網(wǎng)絡(luò)開(kāi)銷;數(shù)據(jù)依次成遞增依賴于服務(wù)器時(shí)間,如變動(dòng)服務(wù)器時(shí)間則存在重復(fù)的情況
Redis基于內(nèi)存、速度庫(kù);使用簡(jiǎn)單;可分布數(shù)據(jù)、擴(kuò)展性強(qiáng)需要獨(dú)立搭建一套服務(wù)、增加了維護(hù)成本;跨應(yīng)用調(diào)用、存在網(wǎng)絡(luò)開(kāi)銷
數(shù)據(jù)庫(kù)自增代碼層面無(wú)需任何特殊處理;利用MySQL特點(diǎn)實(shí)現(xiàn)數(shù)據(jù)遞增并發(fā)性能差;MySQL負(fù)擔(dān)重

“怎么正確設(shè)計(jì)一個(gè)訂單號(hào)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI