Direkt zum Hauptinhalt springen
eLearner.app
Modul 11 · Lektion 2 von 442/57 im Kurs~10 min
Lektionen des Moduls (2/4)

Race Conditions

Es ist einfach zu verstehen, wie eine Datenbank isoliert auf einem einzelnen Terminal funktioniert, aber in einem echten Webszenario gibt es Hunderte von gleichzeitigen „Node/PHP/Go“-Prozessen, die Anfragen senden. Hier entstehen die berühmten Race Conditions.

Das Problem „Verlorenes Update“.

Ein verlorenes Update tritt auf, wenn zwei Threads dieselbe alte Zeile lesen, auf dem JavaScript-Server Berechnungen durchführen und dann das UPDATE zurücksenden, um das Ergebnis zu speichern.

Szenario:

  • Produkt #5 hat 10 Einheiten.
  • Benutzer A kauft eins (Server A liest „10“, berechnet „9“).
  • In derselben Millisekunde kauft Benutzer B einen weiteren, bevor der Kauf von A die COMMIT-Phase abschließt.
  • Server B liest ebenfalls „10“ und berechnet „9“.
  • Server A sendet UPDATE: set quantity = 9.
  • Server B sendet UPDATE: set quantity = 9.
  • Beide glauben, dass sie die Zahl erfolgreich verringert haben. Der Endwert hätte aber 8 Einheiten betragen sollen! Ein Phantomkauf ist verloren gegangen.

Lösung ohne schwere Transaktionen (Atomic Updates)

Anstatt draußen zu lesen und zu rechnen, überlassen Sie dies der Datenbank während des Updates selbst, das immer synchronisiert ist.

SQL
-- Wrong
UPDATE products SET stock = 9 WHERE id = 5;

-- Correct and natively thread-safe
UPDATE products SET stock = stock - 1 WHERE id = 5;

Weitere extreme Anomalien (Dirty Reads & Phantoms)

  • Dirty Read: Sie haben die temporären Daten einer anderen Person gelesen, die noch nicht durch COMMIT bestätigt wurde (und plötzlich zu einem ROLLBACK übergehen könnte, das Sie ungültig macht).
  • Phantom-Lesevorgänge: Sie führen einen Scan aller Zeilen durch, während ein zweiter Thread einen neuen Datensatz einfügt, dann führen Sie einen weiteren Scan während derselben Transaktion durch und stellen auf magische Weise fest, dass der neue Datensatz aus dem Nichts aufgetaucht ist, was die berechneten Finanzberichte gefährdet.
Übung#sql.m11.l2.e1
Versuche: 0Wird geladen…

Ändern Sie den Kundendatensatz atomar für eine kleine Zeichenfolgenmanipulation. Angenommen, wir möchten die „Stadt“ eines Kunden umbenennen, um ein Sternchen hinzuzufügen. Nutzen Sie dazu den eigenen Wert der Zeile für den mit der ID=10 und verketten Sie „- Old“ mit dem aktuellen Wert (verwenden Sie die Postgres-Verkettungspipe ||).

Editor wird geladen…
Hinweis anzeigen

Kunden aktualisieren SET Stadt = Stadt || ' - Alt' WHERE id = 10;

Lösung nach 3 Versuchen verfügbar

Übung#sql.m11.l2.e2
Versuche: 0Wird geladen…

Eine klassische verlorene Aktualisierung passiert bei Zahlungen und Preisen. Nehmen wir an, es gibt eine Notpreiserhöhung: Erhöhen Sie den „unit_price“ der Tabelle „order_items“ (für Produkt 1 von Bestellung 1) um atomare 20 %, d. h. multiplizieren Sie ihn mit 1,2, anstatt den neuen, manuell in JS vorberechneten Preis einzufügen.

Editor wird geladen…
Hinweis anzeigen

UPDATE order_items SET unit_price = unit_price * 1.2 WHERE order_id = 1 AND product_id = 1;

Lösung nach 3 Versuchen verfügbar