Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie erkennt man, dass die Transaktion bereits gestartet wurde?

Das Framework kann nicht wissen, ob Sie eine Transaktion gestartet haben. Sie können sogar $db->query('START TRANSACTION') verwenden von denen das Framework nichts wissen würde, weil es die von Ihnen ausgeführten SQL-Anweisungen nicht parst.

Der Punkt ist, dass es in der Verantwortung der Anwendung liegt, zu verfolgen, ob Sie eine Transaktion gestartet haben oder nicht. Das Framework kann das nicht.

Ich weiß, dass einige Frameworks versuchen, dies zu tun, und verrückte Dinge tun, wie z. B. zu zählen, wie oft Sie eine Transaktion begonnen haben, und sie nur auflösen, wenn Sie eine entsprechende Anzahl von Commit- oder Rollback-Vorgängen durchgeführt haben. Aber das ist völlig falsch, weil keine Ihrer Funktionen wissen kann, ob Commit oder Rollback dies tatsächlich tun oder ob sie sich in einer anderen Verschachtelungsebene befinden.

(Kannst du sagen, dass ich diese Diskussion schon ein paar Mal geführt habe? :-)

Aktualisierung 1: Antrieb ist eine Bibliothek für den Zugriff auf PHP-Datenbanken, die das Konzept der "inneren Transaktion" unterstützt, die nicht festgeschrieben wird, wenn Sie es sagen. Das Beginnen einer Transaktion erhöht nur einen Zähler, und Commit/Rollback verringert den Zähler. Unten ist ein Auszug aus einem Mailinglisten-Thread, in dem ich einige Szenarien beschreibe, in denen es fehlschlägt.

Aktualisierung 2: Doctrine DBAL hat diese Funktion auch. Sie nennen es Transaction Nesting.

Ob Sie es mögen oder nicht, Transaktionen sind "global" und gehorchen nicht der objektorientierten Kapselung.

Problemszenario Nr. 1

Ich rufe commit() auf , werden meine Änderungen übernommen? Wenn ich in einer "inneren Transaktion" laufe, sind sie es nicht. Der Code, der die äußere Transaktion verwaltet, könnte sich für ein Rollback entscheiden, und meine Änderungen würden ohne mein Wissen oder meine Kontrolle verworfen.

Zum Beispiel:

  1. Modell A:Transaktion beginnen
  2. Modell A:Einige Änderungen vornehmen
  3. Modell B:Transaktion beginnen (stille No-Op)
  4. Modell B:Einige Änderungen vornehmen
  5. Modell B:Festschreiben (stille No-Op)
  6. Modell A:Rollback (verwirft sowohl Änderungen an Modell A als auch an Modell B)
  7. Modell B:WTF!? Was ist mit meinen Änderungen passiert?

Problemszenario #2

Eine innere Transaktion wird zurückgesetzt, sie könnte legitime Änderungen verwerfen, die von einer äußeren Transaktion vorgenommen wurden. Wenn die Kontrolle an den äußeren Code zurückgegeben wird, glaubt er, dass seine Transaktion immer noch aktiv und verfügbar ist, um festgeschrieben zu werden. Mit Ihrem Patch könnten sie commit() aufrufen , und da die transDepth jetzt 0 ist, würde es stillschweigend $transDepth setzen auf -1 setzen und true zurückgeben, nachdem nichts übergeben wurde.

Problemszenario #3

Wenn ich commit() aufrufe oder rollback() wenn keine Transaktion aktiv ist, setzt es die $transDepth bis 1. Das nächste beginTransaction() erhöht die Ebene auf 0, was bedeutet, dass die Transaktion weder rückgängig gemacht noch festgeschrieben werden kann. Nachfolgende Aufrufe von commit() wird die Transaktion einfach auf -1 oder weiter dekrementieren, und Sie werden nie in der Lage sein, ein Commit durchzuführen, bis Sie ein weiteres überflüssiges beginTransaction() ausführen um den Pegel wieder zu erhöhen.

Grundsätzlich ist der Versuch, Transaktionen in der Anwendungslogik zu verwalten, ohne der Datenbank die Buchhaltung zu überlassen, eine zum Scheitern verurteilte Idee. Wenn Sie zwei Modelle benötigen, um die explizite Transaktionssteuerung in einer Anwendungsanforderung zu verwenden, müssen Sie zwei DB-Verbindungen öffnen, eine für jedes Modell. Dann kann jedes Modell seine eigene aktive Transaktion haben, die unabhängig voneinander festgeschrieben oder rückgängig gemacht werden kann.