簡體   English   中英

如何生成唯一的訂單號?

[英]How to generate unique order number?

我正在尋找一種生成唯一訂單ID的好方法。 你能看到下面代碼有什么問題嗎?

int customerId = 10000000;

long ticks = DateTime.UtcNow.Ticks;

long orderId = customerId + ticks;

int orderNumber = orderId.GetHashCode();

在創建訂單之前,我將檢查數據庫中的數字是否唯一。

如果要將記錄存儲在數據庫中,則應該真正研究可用於生成唯一代理鍵的功能。 在SQLServer中,這將是一個IDENTITY字段,在Oracle中,它將是一個使用SEQUENCE生成新值的字段。

如果有一個令人信服的理由為什么你不能使用你的數據庫來生成一個唯一的密鑰,你應該看一下類似Guid東西 - 它比日期時間操作具有更高概率的mucher來生成一個唯一值。 Guid可以簡單地轉換為字符串,因此在這種情況下您的標識符將是一個字符串。

你用哈希做什么並不是一個好主意 - 沒有任何關於哈希值得特別注意的事情 - 在很多情況下它們確實會發生碰撞。 Guids - 不提供100%保證機器的唯一性但在一台機器上它們應始終是唯一的。 甚至在機器上,他們碰撞的機會極其遙遠。 此外,使用機器時間作為構建潛在價值的方式受競爭條件的影響(如Eric所述)。

Guids是128位值,因此您不能將它們表示為簡單的intlong 它需要您使用字符串作為您的ID ,在您的情況下可能會或可能不會,這取決於其他考慮因素(例如您是否控制數據模型)。 如果可以使用它們,使用Guid非常簡單:

string customerId = Guid.NewGuid().ToString(); // fetch new guid and save as string
string orderNumber = Guid.NewGuid().ToString(); // same story here...

如果您確實必須使用數字標識符,並且您願意放棄在多個服務器上輕松擴展應用程序,則可以使用自動遞增的全局數字來提供唯一鍵。 在應用程序啟動時,您必須使用數據庫中的下一個可用值(max + 1)為此數字設定種子。 然后,您還必須保護此值不受多個線程的並發使用的影響。 我會把這個責任包括在一個課程中:

class static UniqueIDGenerator 
{
    // reads Max+1 from DB on startup
    private static long m_NextID = InitializeFromDatabase(); 

    public static long GetNextID() { return Interlocked.Increment( ref m_NextID ); }
}


編輯: 在這個時代,在應用程序層而不是在數據庫中生成唯一ID的令人信服的理由非常罕見。 您應該真正使用數據庫提供的功能。

假設您有兩個相差100的客戶ID,並且它們碰巧訂單相隔100個單位。 你的獨特性就在窗外。

你說你要檢查數據庫的唯一性; 如果發生碰撞,你不會說你要做什么。 你也沒有說你將如何處理競爭條件; 假設同時創建了兩個沖突訂單ID,數據庫中也沒有。 您在兩個不同的線程上詢問數據庫是否該項是唯一的; 它是。 然后輸入兩者,即使檢查已完成,也違反了唯一性。

這是獲得獨特性的一種非常非常糟糕的方式。 更好的是將其移動到數據庫層。 您可以維護一個全局的線程安全的訂單計數器,並為每個新訂單分配下一個最高訂單號。

順便說一下,多年來我一直在問這個問題的變體作為技術面試問題。 我注意到那些試圖利用時間作為唯一性來源的人和那些沒有被雇用的人之間存在很強的相關性。 時間是獨特的可怕來源; 很多不同的事情可以同時發生。

更糟糕的是使用隨機數。 隨機數是比時間戳更糟糕的唯一性來源。 假設您有一個真正的隨機數生成器,可為訂單ID生成隨機32位整數。 在賠率高於五十五美元之前,您需要多少訂單才能生成兩個具有相同ID的訂單? 這個答案讓很多人感到驚訝:在你有50%的可能性生成兩個相同數量的訂單之前,它只有大約77,000個(只有9300,直到有1%的機會。)

記住:你所追求的是對獨特性的保證 不是一個可能的唯一性,而是一個鐵板保證,一個訂單號只指一個訂單。 如果這就是您所需要的,那么請確保實現它。

那么在數據庫中有一個IDENTITY字段可以幫你嗎?

它還具有以下優點:刪除/取消的訂單號不會被重復使用(這是好的,甚至可能是會計要求)。

如果您使用的是SQL Server,那么您應該查找IDENTITY規范。 它可以讓您輕松快捷地完成此任務。

您的解決方案並不是唯一的,因為系統中的事情可能發生得如此之快,以至於兩個進程(按順序或同時運行)可以獲得相同的tick值。

我將使用IDENTITY列,如果不是,請使用System.Guid.NewGuid()為您生成GUID。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM