PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wie Eindeutigkeit einer Bestellnummer sicherstellen...


coder42
26.05.2008, 11:00:57
Hallo!

Ich arbeite gerade an einem kleinen Shopsystem. Beim Abschluss der Bestellung soll ein neuer Bestell-Datensatz angelegt werden. Hierzu gibt es in einer MySQL Datenbank die Tabelle "Bestellungen", wobei zu jeder Bestellung eine eindeutige Bestellnummer gehört.

Die Bestellnummer ist keine einfache Nummer (1235) sondern setzt sich aus verschiedenen Bestandteilen zusammen, z.B. "2008-CU-12345". Man kann die Nummer daher nicht einfach automatisch hochzählen, sondern muss sie "zusammenbauen"

Ich suche nun nach einer Möglichkeit die Eindeutigkeit einer Kundennummer sicherzustellen. Bis jetzt bin ich so vorgegangen:

1. Bestellnummer der letzten Bestellung ermitteln.
2. Neue Bestellnummer zusammenbauen: ...12345 -> ...12346
3. Neuen Datensatz anlegen.

Nun ist es es aber möglich, dass zwei Bestellungen gleichzeitig ausgelöst werden und somit zwei mal die gleiche Bestellnummer erstellt wird. Das ist zwar relativ unwahrscheinlich aber schon vorgekommen...

Wie kann ich so etwas verhindern?

"Bestellnummer" ist in der Tabelle schon als "unique" deklariert, in obigem Fall erhält also ein Script beim Einfügen die Rückmeldung, dass der Datensatz nicht eingefügt werden kann, weil die Kundennummer schon vorhanden ist...

Jetzt könnte man natürlich einfach nochmal einfügen. Aber theoretisch könnte ja wieder ein anderer Prozess dazwischen kommen, etc...

Klar, wird das in der Praxis nicht sonderlich oft vorkommen, aber es müsste doch eine sichere Methode geben, solche Dinge zu umschiffen...

Ich habe es schon mit einem SubSelect im INSERT versucht. Da die Bestellnummer jedoch recht kompliziert aufgebaut ist, ist es mir nicht gelungen in einem Schritt die vorherige Nummer abzufragen und gleichzeitig die neue Nummer aufzubauen (Muss ja alles in dem Query passieren). Zudem habe ich herausgefunden, dass man beim SubSelect nicht auf die gleiche Tabelle zugreifen kann, auf die sich das INSERT bezieht...

Eine einfache Lösung wäre eine Transaktion, die Tabellen haben jedoch das Format MyISAM und das kann ich auch nicht ändern.

Hat also jemand eine Idee, wie ich hier die Eindeutigkeit sicherstelle?

Besten Dank
Ares

knight1
26.05.2008, 11:56:37
Hi coder42,
eine Möglichkeit wäre, denke ich, in der Tabelle das Feld der Bestellnummer auf UNIQUE zu setzen.
So lässt schon MySQL keine doppelten Bestellnummern zu und liefert dir aufjedenfall einen Fehler wenn Du eine Bestellnummer doppelt speichern willst.
Das könnte dann im Script abgefangen und entsprechend drauf reagiert werden.

Das wäre so meine Idee.


Kai aka Knight1

coder42
26.05.2008, 12:03:54
Das Feld ist ja schon "unique".....

"Bestellnummer" ist in der Tabelle schon als "unique" deklariert, in obigem Fall erhält also ein Script beim Einfügen die Rückmeldung, dass der Datensatz nicht eingefügt werden kann, weil die Kundennummer schon vorhanden ist...

Jetzt könnte man natürlich einfach nochmal einfügen. Aber theoretisch könnte ja wieder ein anderer Prozess dazwischen kommen, etc...

Wenn das Einfügen fehlschlägt, weil die Bestellnummer zwischenzeitig schon einem anderen Prozess gesetzt wurde, muss ich die Bestellnummer neu berechnen und dann wieder einfügen. Nun kann das gleiche Problem aber wieder auftreten. Theoretisch kann der aktuelle Prozess also nie seine Bestellung einfügen, weil ihm immer ein anderer Prozess die Bestellnummer "wegschnappt".

Das ist natürlich ein theoretisches Problem, in der Praxis wird es der Prozess wohl schaffen nach einigen Versuchen die eine Bestellnummer zu ergattern, die nicht weggeschnappt wird. Aber für dieses Problem muss es doch eine saubere Lösung geben...

knight1
26.05.2008, 13:16:02
Das Feld ist ja schon "unique".....

Sorry, da hatte ich nicht gründlich genug gelesen.

Mir fällt da adhoc nichts anderes ein als dies Rekrusiv zu machen und bei jeder per Script generierten Bestellnummer auf die Datenebank gegen zuprüfen ob die Bestellnummer schon existiert.
So mache ich es auch bei meinem Projekt mit der automatischen Generierung der Mitgliedsnummer wenn ein Mitglied eingetragen wird.


Kai aka Knight1

nem75
26.05.2008, 16:04:57
Das Feld ist ja schon "unique".....
Das ist natürlich ein theoretisches Problem, in der Praxis wird es der Prozess wohl schaffen nach einigen Versuchen die eine Bestellnummer zu ergattern, die nicht weggeschnappt wird. Aber für dieses Problem muss es doch eine saubere Lösung geben...

Sauber ist die Lösung. Vielleicht nicht die eleganteste, aber sauber schon. Sauberer jedenfalls, als statt UNIQUE einfach vor jedem INSERT ein SELECT zu machen um herauszufinden, ob die Nummer schon vergeben ist. ;)

Die einzige andere Möglichkeit, die mir einfällt: die Bestellnummer mit hilfe einer einfachen, fortlaufenden Nummer berechnen. Also dass du in deiner Tabelle schon eine ganz normale Auto-Inkrement ID-Spalte für die Bestellnummern hast, und auf Grundlage dieser ID dann im Code deine nach außen kommunizierbare Bestellnummer zusammenbaust.

Würde nebenbei auch weniger Speicher in der DB verbrauchen (INT: 4 byte, CHAR: 1 byte pro Zeichen).