Heim  >  Artikel  >  Backend-Entwicklung  >  Zwei Lösungen zur Implementierung von MySQL-verschachtelten Transaktionen in PHP

Zwei Lösungen zur Implementierung von MySQL-verschachtelten Transaktionen in PHP

WBOY
WBOYOriginal
2016-08-08 09:25:19992Durchsuche

1. Ursprung des Problems

In der offiziellen Dokumentation von MySQL gibt es eine klare Aussage, dass verschachtelte Transaktionen nicht unterstützt werden:

1. Transaktionen können nicht verschachtelt werden, wenn Sie eine START TRANSACTION-Anweisung oder eines ihrer Synonyme ausgeben

Aber wenn wir ein komplexes System entwickeln, ist es unvermeidlich, dass wir versehentlich Transaktionen in Transaktionen einbetten. Beispielsweise ruft Funktion A Funktion B auf, Funktion A verwendet eine Transaktion und Funktion B wird in der Transaktion aufgerufen Da es sich ebenfalls um eine Transaktion handelt, kommt es zu einer Transaktionsverschachtelung. Zu diesem Zeitpunkt sind die Angelegenheiten von A eigentlich von geringer Bedeutung. Es wird im obigen Dokument erwähnt und die einfache Übersetzung lautet:

1. Bei der Ausführung einer START TRANSACTION-Anweisung wird implizit eine Commit-Operation ausgeführt. Daher müssen wir 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. Zur Erinnerung: Die Benennung von Funktionen und Variablen in diesen beiden Frameworks ist relativ intuitiv, obwohl sie sehr langwierig aussieht. Sie können die Bedeutung der Funktion oder Variablen jedoch direkt durch die Benennung erkennen, sodass auf den ersten Blick kein so großes Durcheinander entsteht. Ich war schockiert :)

2. Lösung der Lehre

Werfen wir zunächst einen Blick auf den Code zum Erstellen einer Transaktion in Doctrine (irrelevanter Code entfernt):

[php] Klartext anzeigen

  1. /**  
  2. * Autor http://www.lai18.com  
  3. * Datum 2015-04-19  
  4. * Version 1  
  5. **/ 
  6. öffentliche Funktion beginTransaction()
  7. {
  8. $this->_transactionNestingLevel;
  9.  if ($this->_transactionNestingLevel == 1) {
  10. $this->_conn->beginTransaction();
  11. } else if ($this->_nestTransactionsWithSavepoints) {
  12. $this->createSavepoint($this->_getNestedTransactionSavePointName());
  13. }
Die erste Zeile dieser Funktion verwendet einen _transactionNestingLevel, um die aktuelle Verschachtelungsebene zu identifizieren, das heißt, es gibt noch keine Verschachtelung, dann verwenden Sie die Standardmethode, um START TRANSACTION auszuführen, und es ist in Ordnung ist größer als 1. Das heißt, wenn eine Verschachtelung vorliegt, hilft sie uns beim Erstellen eines Sicherungspunkts. Dieser Sicherungspunkt kann als Transaktionsaufzeichnungspunkt verstanden werden. Wenn ein Rollback erforderlich ist, können wir nur zu diesem Punkt zurückkehren. Dann schauen Sie sich die RollBack-Funktion an:

[php] Klartext anzeigen

  1.     1. /**  
  2. * Autor http://www.lai18.com  
  3. * Datum 2015-04-19  
  4. * Version 1  
  5. **/   
  6. öffentliche Funktion rollBack()  
  7.   
  8. {  
  9.   
  10.     if ($this->_transactionNestingLevel == 0) {  
  11.   
  12.         throw ConnectionException::noActiveTransaction();  
  13.   
  14.     }  
  15.     if ($this->_transactionNestingLevel == 1) {  
  16.   
  17.         $this->_transactionNestingLevel = 0;  
  18.   
  19.         $this->_conn->rollback();  
  20.   
  21.         $this->_isRollbackOnly = false;  
  22.   
  23.     } else if ($this->_nestTransactionsWithSavepoints) {  
  24.   
  25.         $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());  
  26.   
  27.         --$this->_transactionNestingLevel;  
  28.   
  29.     } else {  
  30.   
  31.         $this->_isRollbackOnly = true;  
  32.   
  33.         --$this->_transactionNestingLevel;  
  34.   
  35.     }  
  36.   
  37. }   

可以看到处理的方式也很简单, 如果level是1, 直接rollback, 否则就回滚到前面的savepoint.然后我们继续看下commit函数:

[php] Klartext anzeigen

  1.     1. /**  
  2. * Autor http://www.lai18.com  
  3. * Datum 2015-04-19  
  4. * Version 1  
  5. **/   
  6. public function commit()  
  7.   
  8. {  
  9.   
  10.     if ($this->_transactionNestingLevel == 0) {  
  11.   
  12.         throw ConnectionException::noActiveTransaction();  
  13.   
  14.     }  
  15.   
  16.     if ($this->_isRollbackOnly) {  
  17.   
  18.         throw ConnectionException::commitFailedRollbackOnly();  
  19.   
  20.     }  
  21.     if ($this->_transactionNestingLevel == 1) {  
  22.   
  23.         $this->_conn->commit();  
  24.   
  25.     } else if ($this->_nestTransactionsWithSavepoints) {  
  26.   
  27.         $this->releaseSavepoint($this->_getNestedTransactionSavePointName());  
  28.   
  29.     }  
  30.     --$this->_transactionNestingLevel;  
  31.   
  32. }   

算了,不费口舌解释这段了吧 :)

三、laravel的解决方案laravel的处理方式相对简单粗暴一些,我们先来看下创建事务的操作:

[php] Klartext anzeigen

  1.     1.   
  2. /**  
  3. * Autor http://www.lai18.com  
  4. * Datum 2015-04-19  
  5. * Version 1  
  6. **/   
  7. öffentliche Funktion beginTransaction()  
  8.   
  9. {  
  10.   
  11.      $this->transactions;  
  12.     if ($this->transactions == 1)  
  13.   
  14.     {  
  15.   
  16.         $this->pdo->beginTransaction();  
  17.   
  18.     }  
  19.   
  20. }   

So einfach么为啥是啥都不做呢?继续往下看rollBack的操作:

[php] Klartext anzeigen

  1.     1. /**  
  2. * Autor http://www.lai18.com  
  3. * Datum 2015-04-19  
  4. * Version 1  
  5. **/   
  6. öffentliche Funktion rollBack()  
  7.   
  8. {  
  9.   
  10.     if ($this->transactions == 1)  
  11.   
  12.     {  
  13.   
  14.         $this->transactions = 0;  
  15.         $this->pdo->rollBack();  
  16.   
  17.     }  
  18.   
  19.     sonst  
  20.   
  21.     {  
  22.   
  23.         --$this->transactions;  
  24.   
  25.     }  
  26.   
  27. }   

明白了吧?只有当当前事务只有一个的时候才会真正的rollback,否则只是将计数做减一操作.这也就是为啥刚才说laravel的处理比较简单粗暴一些, 在嵌套的内层里面实际上是木有真正的事务的,只有最外层一个整体的事务,虽然简单粗暴,但是也解决了在内层新建一个事务时会造成commit的问题.原理就是这个样子了,为了保持完整起见,把commit的代码也copy过来吧!

[php] Klartext anzeigen

  1. public function commit()  
  2.   
  3. {  
  4.   
  5.     if ($this->transactions == 1) $this->pdo->commit();  
  6.     --$this->transactions;  
  7.   
  8. }  

以上就介绍了PHP中实现MySQL嵌套事务的两种解决方案, 包括了方面的内容, 希望对PHP教程有兴趣的朋友有所帮助.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn