2009-04-27 5 views
2

Verursacht dies eine Race-Bedingung mit MySQL (InnoDB):MySQL Race-Conditions

  1. Starten Sie die Transaktion.

  2. Versuchen Sie, aufzunehmen.

  3. Wenn der Datensatz nicht existiert, kehren Sie zurück.

  4. Wenn ein Datensatz existiert, löschen Sie ihn und fügen Sie einen Protokolleintrag hinzu, der besagt, dass er gelöscht wurde.

  5. Ende Transaktion (Festschreibung/Rollback).

Ist es möglich, ein anderer Prozess kurz vor dem Löschschritt in 2b zu starten, um das Vorhandensein des Datensatzes erkennen und dann beide Prozesse eingeben Artikel Einträge in das Protokoll löschen?

Gibt es irgendwelche Vorsichtsmaßnahmen, die ich ergreifen muss?

Danke.

+0

Sehen Sie dieses Verhalten? Oder ist das eine rein theoretische Frage? – Joe

+0

Wenn Sie einen eindeutigen Index für die Protokolltabelle haben, kann der zweite Thread dort keinen doppelten Eintrag hinzufügen und der zweite Thread wird zurückgesetzt. Indizes zur Rettung noch einmal. –

Antwort

4

Verwenden Sie "Select for update" in Schritt 2. Nur ein Prozess kann die Zeile sperren, wodurch das beschriebene Szenario vermieden wird.

+0

Ja, das wirft einige Leute, aber * technisch * ein Löschen ist eine Art Update. – Powerlord

+0

Ich verwende einen ORM, der das verhindert. So können Sie bestätigen, dass dies eine Race Condition ist? – user96747

+0

Ich müsste sagen, ja, es ist eine Race Condition. – Powerlord

0

Ja, es ist möglich, dass eine andere Transaktion die Tabelle überprüft, nachdem Sie sie gelesen haben.

Schlimmer noch, aufgrund der Funktionsweise von Transaktionen, selbst nachdem Sie die Zeile gelöscht haben, werden alle neuen Transaktionen, die gestartet werden, die Zeile sehen, weil Sie das Löschen noch nicht festgeschrieben haben.

SELECT ... FOR UPDATE ist eine Möglichkeit, dies zu verhindern.

LOCK TABLE tablename ist ein anderer.

Leider, da Sie ein ORM verwenden, konnte ich nicht sagen, ob es die Möglichkeit hat, beide zu tun.

1

Journeyman Programmierer, glaube ich, hat die richtige Lösung. Da Sie angegeben haben, dass Sie ein beschädigtes ORM-Tool verwenden (eines, das Ihnen keine Aktualisierung ermöglicht), würde ich vorschlagen, dass Sie Ihre INSERT-Datei in die Protokolltabelle in einen Trigger für die Löschoperation verschieben, um das Duplikat zu vermeiden Eintrag.

1

Starten Sie die Transaktion.

Datensatz löschen/* mit den gleichen Kriterien, die Sie für die Anwendung ‚versuchen Datensatz zu bekommen‘ */

wenn Antwortsatz gibt tatsächlich gelöscht wurde, einen Protokolleintrag hinzufügen.

Ende Transaktion (Festschreibung/Rollback).

Kein Wettlauf mehr.