Race Condition

Hi,

folgendes Konzept überlege ich mir gerade für einen Import.

In dem Import sind Daten die durch die Normalisierung Felder in einer Referenztabellen speichern.
Dazu baue ich mir eine Tabelle im Speicher die alle möglichen Zeilen für die Referenztabelle zwischen speichert. Dann möchte ich einen EXCLUSIVE-Lock auslösen, damit ein paralleler Import nicht gleichzeitig Insert auf diese Referenztabelle ausführt. Nach dem Lock mache ich die SELECTs und die folge INSERTS/UPDATES (evtl später sogar direkt als PG Funktion). Die id Speichere ich mit dann mit in dem lokalen Speicher und hebe zum Schluss den EXCLUSIVE-Lock auf. Nun Commite ich die Transaktion und mache eine neue auf für die eigentlichen Daten. Wenn ich das Richtig verstanden habe, macht EXCLUSIVE-Lock ja nur ein Schreiblock und die normale Anwendung kann problemlos lesen. Schöner wäre natürlich eine Art Insert-Lock, weil die Updates könnte ich auch mit einem SELECT FOR UPDATE machen. Damit würde ich die Lockzeit reduzieren. Aber sowas habe ich nicht gefunden oder hab ich hier was übersehen.

LG

Die Daten, die du schreibst, sind automatisch bis zum Ende deiner Transaktion gelockt - und sind nicht sichtbar (das ist das “A” in ACID).

Du kannst allerdings einen LOCK nicht aufheben, ohne die aktuell laufende Transaktion zu beenden.

ja aber es könnte sein, das der 2 Import versucht den gleichen Datensatz in der Referenztabelle anzulegen. Und das will ich verhindern um Race Conditions zu verhindern.

Das ich den LOCK nicht aufheben kann ohne die Transaktion zu beenden ist mir bewusst und sollte kein Problem sein, da ich das Anlegen der Referenzdaten in einer eigenen Transaktion vorweg machen. Die dürfen sogar bestehen bleiben, wenn später ein Fehler auftritt bei den Nutzdaten. Wichtig ist nur das 2 oder mehrere Imports nicht gleichzeitige versuchen die gleiche Kategorie (nenn ich jetzt zum besseren Verständnis) anlegt. Zwar würde dann der Unique-Constraint greifen, den kann ich aber a) nicht gut auf App-Seite abfangen/behandeln und b) müsste es meine laufende Transaktion beenden (nicht 100% sicher)

Wenn du das nicht in der Anwendung abfangen kannst, wirst du wohl um einen exklusiven LOCK nicht drumherum kommen. Allerdings könntest du dir noch SAVEPOINTs als Zwischenlösung anschauen.

SavePoints nutze ich auch viel, allerdings verstehe ich nicht was mir das hier bringt? Einzig was ich mir vorstellen könnte, ist eine Transaktion für den Import und die Savepoints für die Referenzdaten und für Nutzdaten. Hier hilft es mir aber nicht bei meinem Problem oder? Oder meinst du Savepoints damit nicht die komplette Transaktion abbricht. Aber das schöne ist nur die Crons befüllen die Daten daher denk ich das der Exclusive-Lock optimal ist für mich. Wollte mich auch nur versichern, dass es nicht doch noch ne Art Insert-Lock gibt. Der wäre ja optimal um RaceConditions zu verhindern.

OffTopic:
Alternative hatte ich mir schonmal für ein anderes Projekt überlegt einfach nen Dummy Zeile in die Tabelle zulegen und auf dieser zuerst eine SELECT FOR Update zu machen. Ist zwar nicht schön würde aber bestimmt auch noch gehen. *Erschlagt mich nicht ich weis das so was extrem unschön ist :smiley:

Ehe du mit Dummy-Zeilen anfängst, schlag doch mal “Advisory Locking” nach … das löst - mit weniger Aufwand - das gleiche Problem.

Das kannte ich noch gar nicht. Das hört sich noch besser. Es gibt ja nur die ImportCrons die Inserts durchführen. Sobald ein Datensatz angelegt wird, mach ich das Advisory Locking. Jetzt muss ich nur noch mal in der Doku schauen wie das ist, dass die andere Transaktion die Änderungen sehen können bzw. dann bräuchte ich gar keine Transaktion mehr für die Referenztabellen, also direkt commiten.

Großes Danke!