Überprüfen dieses einfache Stück Code, das einen Generator zu schaffen eindeutige Primärschlüssel in einem Firebird Tabelle verwendet:Wie verschwende ich nicht Generator-Werte, wenn Sie sie Serverseite mit Firebird verwenden?
CREATE OR ALTER TRIGGER ON_BEFOREINSERT_PK_BOOKING_ITEM FOR BOOKING_ITEM BEFORE INSERT POSITION 0
AS
BEGIN
IF ((NEW.booking_item_id IS NULL) OR (NEW.booking_item_id = 0)) THEN BEGIN
SELECT GEN_ID(LastIdBookingItem, 1) FROM RDB$DATABASE INTO :NEW.booking_item_id;
END
END!
Dieser Trigger Greifern und erhöht dann einen erzeugten Wert zuordnet somit für die Buchung Item ID Schaffung ein automatisch inkrementierten Schlüssel für die Tabelle BOOKING_ITEM. Der Trigger überprüft sogar, dass der Buchungs-ID noch kein Wert zugewiesen wurde.
Das Problem ist, dass der automatisch inkrementierte Wert verloren geht (verschwendet wird), wenn der BOOKING_ITEM-Datensatz aus irgendeinem Grund nicht gebucht werden kann.
Ich habe ein paar Ideen, wie man diese Verschwendung vermeiden kann, aber Bedenken über jeden einzelnen haben. Hier sind sie:
Decrement der Zähler, wenn ein Buchungsfehler auftritt. Innerhalb des Triggers richte ich einen try-except-Block ein (try-excess-Blöcke existieren sogar in Firebird PSQL?) Und führe einen
SELECT GEN_ID(LastIdBookingItem, -1) FROM RDB$DATABASE
für Post-Exceptions aus. Würde das funktionieren? Was passiert, wenn eine andere Transaktion hereinkommt und den Generator inkrementiert, bevor ich ihn dekrementiere? Das würde wirklich alles durcheinander bringen.Verwenden Sie eine temporäre ID. Setzen Sie die ID auf einen eindeutigen Temperaturwert, den ich beim Trigger AFTER INSERT auf den Generatorwert ändern möchte. Diese Methode fühlt sich etwas künstlich an und erfordert einen Weg, der sicherstellt, dass die Temp-ID eindeutig ist. Aber was, wenn die booking_item_id clientseitig bereitgestellt wurde, wie würde ich das von einer temporären ID unterscheiden? Plus ich brauche einen anderen Auslöser
Verwenden Sie Transaktionssteuerung. Dies ist wie Option 1. Mit Ausnahme, dass ich den try-except-Block verwende, um den Generator zurückzusetzen, starte ich eine Transaktion und rolle sie dann zurück, wenn der Datensatz nicht posten kann. Ich kenne die Syntax für die Verwendung der Transaktionskontrolle nicht. Ich dachte, ich hätte irgendwo gelesen, dass SAVEPOINT/SET TRANSACTION in PSQL nicht erlaubt ist. Außerdem müsste der Rollback im AFTER INSERT-Trigger stattfinden, damit ich erneut einen Trigger brauche.
Sicherlich ist dies ein Problem für jeden Firebird-Entwickler, die Generatoren verwenden möchte. Irgendwelche anderen Ideen? Gibt es etwas, das mir fehlt?
Die Antwort ist die gleiche wie für alle anderen DBMS, die Sequenzen verwenden: Mach dir keine Sorgen. Sequenzen sind nicht lückenlos und ihr Wert ist bedeutungslos. Ihr einziger Zweck ist es, als künstlicher Primärschlüssel zu dienen. Nichts mehr. Wenn Ihre Anwendung lückenlose Werte verwendet, können Sie einfach keine Sequenz verwenden (durchsuchen Sie diese Site nach "Lückenlose Sequenz" für Alternativen). –
Ich suche diese Seite nach "Lückenlose Sequenz" für Alternativen. Vielen Dank. Meistens hast du Recht "Wen kümmert es", aber für einige Tabellen erzeuge ich eine Sequenznummer und verwende sie als, sagen wir, eine Rechnungsnummer. Gelegentlich bitten uns unsere Wirtschaftsprüfer, Rechnungen X bis X + n zu erstellen. Sicherlich müssen nicht alle Rechnungen aktiv sein, einige können storniert werden, aber sie fragen sich, ob irgendwelche Nummern fehlen. Sie stellen Fragen wie "Wo ist die Rechnung 12345?" –
Richtig, für Rechnungsnummern benötigen Sie etwas anderes. Eine Sequenz ist dafür nicht geeignet. –