In diesem Artikel werden hauptsächlich zwei Lösungen für die Implementierung verschachtelter MySQL-Transaktionen in PHP vorgestellt. Dieser Artikel analysiert die Implementierungsmethoden von Doctrine und Laravel und extrahiert sie zur Analyse und Zusammenfassung.
1. Ursprung des Problems
In der offiziellen Dokumentation von MySQL heißt es eindeutig, dass verschachtelte Transaktionen nicht unterstützt werden:
Transactions cannot be nested. This is a consequence of the implicit commit performed for any current transaction when you issue a START TRANSACTION statement or one of its synonyms.
Aber es ist unvermeidlich, wenn wir ein komplexes System entwickeln. Transaktionen können verschachtelt sein Beispielsweise ruft Funktion A unbeabsichtigt Funktion B auf, Funktion A verwendet eine Transaktion und ruft Funktion B innerhalb einer Transaktion auf, sodass es zu einer Transaktionsverschachtelung kommt. Zu diesem Zeitpunkt sind die Angelegenheiten von A eigentlich von geringer Bedeutung. Es wird im obigen Dokument erwähnt. Eine einfache Übersetzung lautet:
当执行一个START TRANSACTION指令时,会隐式的执行一个commit操作。
Wir müssen also die Verschachtelung von Transaktionen auf der Ebene der Systemarchitektur unterstützen. Glücklicherweise unterstützen einige ausgereifte ORM-Frameworks die Verschachtelung, beispielsweise Doctrine oder Laravel. Schauen wir uns als Nächstes an, wie diese beiden Frameworks implementiert werden.
Freundliche Erinnerung: Die Benennung von Funktionen und Variablen in diesen beiden Frameworks ist relativ intuitiv. Obwohl sie sehr lang aussieht, können Sie die Bedeutung der Funktion oder Variablen direkt durch die Benennung erkennen, also hatte ich keine Angst Als ich so ein großes Durcheinander sah :)
2. Doctrines Lösung
Werfen wir zunächst einen Blick auf den Code zum Erstellen einer Transaktion in Doctrine (nicht verwandter Code). ):
public function beginTransaction() { ++$this->_transactionNestingLevel; if ($this->_transactionNestingLevel == 1) { $this->_conn->beginTransaction(); } else if ($this->_nestTransactionsWithSavepoints) { $this->createSavepoint($this->_getNestedTransactionSavePointName()); } }
Die erste Zeile dieser Funktion verwendet einen _transactionNestingLevel, um die aktuelle Verschachtelungsebene zu identifizieren, d. h., es gibt noch keine Verschachtelung, dann verwenden Sie die Standardmethode, um sie auszuführen ist in Ordnung. Wenn es größer als 1 ist, das heißt, wenn eine Verschachtelung vorliegt, können wir einen Sicherungspunkt erstellen, der als Transaktionsaufzeichnungspunkt verstanden werden kann .
Dann werfen Sie einen Blick auf die RollBack-Funktion:
public function rollBack() { if ($this->_transactionNestingLevel == 0) { throw ConnectionException::noActiveTransaction(); } if ($this->_transactionNestingLevel == 1) { $this->_transactionNestingLevel = 0; $this->_conn->rollback(); $this->_isRollbackOnly = false; } else if ($this->_nestTransactionsWithSavepoints) { $this->rollbackSavepoint($this->_getNestedTransactionSavePointName()); --$this->_transactionNestingLevel; } else { $this->_isRollbackOnly = true; --$this->_transactionNestingLevel; } }
Sie sehen, dass die Verarbeitungsmethode auch sehr einfach ist. Wenn die Ebene 1 ist, führen Sie ein direktes Rollback durch, andernfalls ein Rollback zum vorherigen Speicherpunkt.
Dann schauen wir uns weiter die Commit-Funktion an:
public function commit() { if ($this->_transactionNestingLevel == 0) { throw ConnectionException::noActiveTransaction(); } if ($this->_isRollbackOnly) { throw ConnectionException::commitFailedRollbackOnly(); } if ($this->_transactionNestingLevel == 1) { $this->_conn->commit(); } else if ($this->_nestTransactionsWithSavepoints) { $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); } --$this->_transactionNestingLevel; }
Vergiss es, lass uns das ohne Probleme erklären :)
3. Die Lösung von Laravel
Die Verarbeitungsmethode von Laravel ist relativ einfach und grob. Schauen wir uns zunächst den Vorgang zum Erstellen einer Transaktion an:
public function beginTransaction() { ++$this->transactions; if ($this->transactions == 1) { $this->pdo->beginTransaction(); } }
Wie fühlst du dich? So einfach, oder? Stellen Sie zunächst fest, wie viele Transaktionen es derzeit gibt. Wenn es die erste ist, wird die Transaktion gestartet. Ansonsten wird nichts unternommen. Schauen Sie sich weiterhin die Funktionsweise von RollBack an:
public function rollBack() { if ($this->transactions == 1) { $this->transactions = 0; $this->pdo->rollBack(); } else { --$this->transactions; } }
Verstehen Sie? Nur wenn nur eine aktuelle Transaktion vorhanden ist, wird sie wirklich zurückgesetzt, andernfalls wird die Anzahl nur um eins verringert. Aus diesem Grund habe ich gerade gesagt, dass die Verarbeitung von Laravel relativ einfach und grob ist. Es gibt tatsächlich keine echten Transaktionen in der äußersten Schicht. Obwohl sie einfach und grob ist, löst sie das Problem Wenn die innere Ebene eine neue Transaktion erstellt, führt dies zu Festschreibungsproblemen. Das Prinzip ist so: Der Vollständigkeit halber kopieren Sie auch den Commit-Code!
public function commit() { if ($this->transactions == 1) $this->pdo->commit(); --$this->transactions; }
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.
Verwandte Empfehlungen:
So verwenden Sie die Funktion mb_detect_encoding in PHP
So verwenden Sie die SMTP-Sendeunterstützung in PHP Angehängte E-Mail
So implementieren Sie den asynchronen Supervisor-Ausführungsprozess in PHP mit dem Laravel-Framework
Das obige ist der detaillierte Inhalt vonSo implementieren Sie verschachtelte MySQL-Transaktionen in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!