Wie generiere ich eine eindeutige Bestellnummer?

8

Ich bin auf der Suche nach einer guten Möglichkeit, eine eindeutige Bestell-ID zu generieren. Können Sie irgendwelche Probleme mit dem folgenden Code sehen?

%Vor%

Ich werde prüfen, ob die Nummer in der Datenbank eindeutig ist, bevor die Bestellung erstellt wird.

    
Junior Developer 15.02.2010, 16:06
quelle

6 Antworten

24

Wenn Sie Ihre Datensätze in einer Datenbank speichern, sollten Sie sich die verfügbaren Möglichkeiten zum Generieren eindeutiger Ersatzschlüssel ansehen. In SQL Server wäre dies ein IDENTITY Feld und in Oracle wäre es ein Feld, das ein SEQUENCE um einen neuen Wert zu generieren.

Wenn es einen zwingenden Grund gibt, warum Sie Ihre Datenbank nicht zum Generieren eines eindeutigen Schlüssels verwenden können, sollten Sie sich etwas wie a Guid - das hat eine höhere Wahrscheinlichkeit als Datum-Zeit-Manipulation, um einen eindeutigen Wert zu erzeugen. Guids können trivial in Strings konvertiert werden, so dass Ihr Bezeichner in diesem Fall eine Zeichenfolge wäre.

Was Sie mit Hashes tun, ist keine gute Idee. - Nichts, was Hashes ist, wird einzigartig sein - und in vielen Fällen kollidieren sie tatsächlich. Guids - bieten keine hundertprozentige Garantie für die Einzigartigkeit übergreifender Maschinen , aber auf einer einzigen Maschine sollten sie immer einzigartig sein. Und selbst bei Maschinen sind ihre Kollisionswahrscheinlichkeiten extrem gering. Auch die Verwendung der Maschinenzeit als eine Möglichkeit, den zugrunde liegenden Wert aufzubauen, hängt von den Rennbedingungen ab (wie die von Eric beschriebenen).

Guids sind 128-Bit-Werte, daher können Sie sie nicht als einfache int oder long darstellen. Dazu müssten Sie die Zeichenfolge als Ihre IDs verwenden , was in Ihrem Fall möglicherweise möglich ist oder auch nicht, abhängig von anderen Überlegungen (z. B. ob Sie das Datenmodell steuern oder nicht). Wenn Sie sie verwenden können, ist die Verwendung eines Guid sehr einfach:

%Vor%

Wenn Sie wirklich eine numerische Kennung verwenden müssen und bereit sind, die Skalierung Ihrer Anwendung auf mehrere Server aufzugeben, können Sie eine globale Nummer mit automatischer Erhöhung verwenden, um einen eindeutigen Schlüssel bereitzustellen. Sie würden Sie müssen diese Nummer beim Start der Anwendung mit dem nächsten verfügbaren Wert (max + 1) aus Ihrer Datenbank säen. Sie müssten diesen Wert dann auch vor der gleichzeitigen Verwendung aus mehreren Threads schützen. Ich würde diese Verantwortung in eine Klasse einschließen:

%Vor%


BEARBEITEN: Heutzutage sind zwingende Gründe für die Generierung eindeutiger IDs in Ihrer Anwendungsschicht und nicht in der Datenbank sehr ungewöhnlich. Sie sollten wirklich die Funktionen verwenden, die die Datenbank bietet.

    
LBushkin 15.02.2010 16:10
quelle
14

Angenommen, Sie haben zwei Kunden-IDs, die sich um 100 unterscheiden, und sie machen beide eine Bestellung, die 100 Zeiteinheiten voneinander entfernt ist. Ihre Einzigartigkeit ist gerade aus dem Fenster gegangen.

Sie sagen, dass Sie die Datenbank auf Eindeutigkeit prüfen werden; Sie sagen nicht, was Sie tun werden, wenn es zu einer Kollision kommt. Sie sagen auch nicht, was Sie wegen der Rassenbedingungen tun werden; Angenommen, zwei kollidierende Auftrags-IDs werden zur gleichen Zeit erstellt, und beide befinden sich nicht in der Datenbank. Sie fragen die Datenbank nach zwei verschiedenen Threads, ob das Element eindeutig ist. es ist. Sie geben beide ein und die Eindeutigkeit wurde verletzt, obwohl die Prüfung durchgeführt wurde.

Dies ist ein wirklich, wirklich schlechter Weg, um Einzigartigkeit zu bekommen. Was wäre besser, dies in die Datenbankschicht zu verschieben. Sie können einen globalen, Thread-sicheren Zähler für Bestellungen verwalten und jeder neuen Bestellung die nächsthöhere Bestellnummer zuweisen.

Übrigens habe ich diese Frage seit vielen Jahren als technische Interviewfrage gestellt. Ich habe eine starke Korrelation zwischen der Gruppe von Menschen, die versuchen, die Zeit als Quelle der Einzigartigkeit zu nutzen, und der Gruppe von Menschen, die nicht angestellt werden, festgestellt. Die Zeit ist eine Quelle der Einzigartigkeit; viele verschiedene Dinge können gleichzeitig passieren.

Was noch schlimmer ist, ist die Verwendung von Zufallszahlen. Zufallszahlen sind eine noch schlechtere Quelle der Eindeutigkeit als Zeitstempel. Angenommen, Sie haben einen echten Zufallszahlengenerator, der zufällige 32-Bit-Ganzzahlen für Auftrags-IDs generiert. Wie viele Aufträge müssen Sie haben, bevor die Chancen besser sind als 50:50, dass Sie zwei Aufträge mit derselben ID generiert haben? Die Antwort überrascht eine Menge Leute: Es ist nur etwa 77.000, bevor es eine Chance von 50% gibt, dass Sie zwei Aufträge mit der gleichen Nummer generiert haben (und nur 9300, bis eine Chance von 1% besteht.)

Denken Sie daran: Was Sie wollen, ist eine Garantie der Einzigartigkeit. Keine wahrscheinliche Einzigartigkeit, sondern eine eiserne Garantie, dass sich eine Bestellnummer auf genau eine Bestellung bezieht. Wenn Sie das brauchen, dann stellen Sie sicher, dass Sie das implementieren.

    
Eric Lippert 15.02.2010 16:13
quelle
7

Wie wäre es mit einem IDENTITY-Feld in der Datenbank für Sie?

Es hat auch den Vorteil, dass gelöschte / stornierte Bestellnummern nicht wiederverwendet werden (was gut oder sogar für die Buchhaltung erforderlich ist).

    
user151323 15.02.2010 16:07
quelle
0

Wenn Sie SQL Server verwenden, sollten Sie die IDENTITY-Spezifikation nachschlagen. Es ermöglicht Ihnen dies mit Leichtigkeit und Geschwindigkeit.

Ihre Lösung ist nicht eindeutig, da Dinge im System so schnell passieren können, dass zwei Prozesse, die entweder nacheinander oder gleichzeitig ausgeführt werden, denselben Tick-Wert erhalten können.

    
Dave Markle 15.02.2010 16:10
quelle
0

Ich würde die IDENTITY-Spalte verwenden und wenn nicht, benutze System.Guid.NewGuid (), um eine GUID für dich zu generieren.

    
itsmatt 15.02.2010 16:12
quelle

Tags und Links