Transaktionen
Drupal unterstützt auch Transaktionen, einschließlich einer transparenten Fallback-Option für Datenbanken, die keine Transaktionen unterstützen. Transaktionen können jedoch ziemlich kompliziert werden, wenn Sie versuchen, zwei Transaktionen gleichzeitig zu starten. Das Verhalten hängt in diesem Fall auch von der Datenbank ab.
Ein ähnliches Problem gibt es bei verschachtelten Locks in C / C++. Wenn der Code bereits Lock A erhalten hat und versucht, Lock A erneut zu erhalten, wird der Code blockiert. Wenn Sie Code schreiben, der überprüft, ob er bereits einen Lock besitzt und versucht, ihn nicht erneut zu erhalten, vermeiden Sie eine Deadlock-Situation, können aber den Lock zu früh freigeben.
In SQL haben wir dasselbe Problem. Wenn Ihr Code sich bereits in einer Transaktion befindet, hat das Starten einer neuen Transaktion die unerwartete und unerwünschte Folge, die aktuelle Transaktion zu committen und eine neue zu starten.
Java löst das Problem der Verschachtelung mit seinen Locks, indem es Unterstützung für eine Verschachtelungsstruktur implementiert, ähnlich wie in unserem folgenden Test. Java erlaubt es, Funktionen als „synchronisiert“ zu markieren, wodurch die Funktion wartet, bis sie den Lock erhält, bevor sie ausgeführt wird, und den Lock freigibt, wenn er nicht mehr benötigt wird. Ruft eine synchronisierte Funktion eine andere im selben Klassenkontext auf, verfolgt Java die Verschachtelung des Locks. Die äußere Funktion erhält den Lock, die innere Funktion führt keine Lock-Operationen aus, und die äußere Funktion gibt den Lock beim Rückgabepunkt frei.
Obwohl wir in PHP keine Funktionen als „transaktional“ deklarieren können, können wir die Java-Logik der Verschachtelung emulieren, indem wir Objekte mit Konstruktoren und Destruktoren verwenden. Die Funktion ruft einfach „$transaction = $connection->startTransaction()“ als erste (oder fast erste) Operation auf, um sich selbst transaktional zu machen. Ruft eine transaktionale Funktion eine andere auf, schachtelt unsere Transaktionsabstraktion diese, ohne innerhalb der inneren Verschachtelung transaktionale Operationen auszuführen (soweit es die Datenbank sieht).
Um eine neue Transaktion zu starten, rufen Sie einfach $transaction = $connection->startTransaction(); in Ihrem eigenen Code auf. Die Transaktion bleibt offen, solange die Variable $transaction im Gültigkeitsbereich verbleibt. Wenn $transaction zerstört wird, wird die Transaktion committed. Wenn Ihre Transaktion in einer anderen verschachtelt ist, verfolgt Drupal jede Transaktion und commitet nur die äußerste Transaktion, wenn das letzte Transaktionsobjekt den Gültigkeitsbereich verlässt, also wenn alle entsprechenden Anfragen erfolgreich abgeschlossen wurden.
Sie müssen den Rückgabewert von $connection->startTransaction(); einer Variablen zuweisen, wie im Beispiel gezeigt. Wenn Sie die Methode aufrufen, ohne den Rückgabewert einer Variablen zuzuweisen, wird Ihre Transaktion sofort committed, was sie nutzlos macht.
Das Rollback einer Transaktion wird in Drupal 8 vom Verbindungsobjekt ($connection->rollBack()) verwaltet, sollte aber normalerweise über die Transaktions-Wrapper-Methode ($action->rollBack()) erfolgen. Der Grund, warum das Rollback über die Methode rollBack() der Transaktion erfolgen sollte, liegt darin, dass es die Transaktion anhand ihres Namens zurücksetzt, während $connection->rollBack() standardmäßig den Namen drupal_transaction verwendet und unerwünschte Ergebnisse bei Verwendung mit verschachtelten Transaktionen verursachen kann.
Beispiel:
function my_transaction_function() { // Die Transaktion wird hier geöffnet. $transaction = $connection->startTransaction(); try { $id = $connection->insert('example') ->fields([ 'field1' => 'mystring', 'field2' => 5, ]) ->execute(); my_other_function($id); return $id; } catch (Exception $e) { $transaction->rollBack(); watchdog_exception('my_type', $e); } // Sie können $transaction hier aus dem Gültigkeitsbereich gehen lassen und die Transaktion wird // automatisch committed, falls sie nicht bereits zurückgerollt wurde. // Wenn Sie jedoch noch mehr Arbeit zu erledigen haben, wollen Sie die Transaktion // selbst commiten, wie folgt: $transaction->commit(); // Mehr Code hier, der außerhalb der Transaktion liegt. } function my_other_function($id) { // Die Transaktion ist hier noch offen. if ($id % 2 == 0) { $connection->update('example') ->condition('id', $id) ->fields(['field2' => 10]) ->execute(); } }
Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.