一、问题起源
在MySQL的官方文档中有明确的说明不支持嵌套事务:
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.
当执行一个START TRANSACTION指令时,会隐式的执行一个commit操作。
友情提示,这两个框架的函数和变量的命名都比较的直观,虽然看起来很长,但是都是通过命名就能直接得知这个函数或者变量的意思,所以不要一看到那么一大坨就被吓到了 :)
二、doctrine的解决方案
首先来看下在doctrine中创建事务的代码(干掉了不相关的代码):
public function beginTransaction() { ++$this->_transactionNestingLevel; if ($this->_transactionNestingLevel == 1) { $this->_conn->beginTransaction(); } else if ($this->_nestTransactionsWithSavepoints) { $this->createSavepoint($this->_getNestedTransactionSavePointName()); } }
然后看下rollBack函数:
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; } }
然后我们继续看下commit函数:
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; }
三、laravel的解决方案
laravel的处理方式相对简单粗暴一些,我们先来看下创建事务的操作:
public function beginTransaction() { ++$this->transactions;if ($this->transactions == 1) { $this->pdo->beginTransaction(); } }
public function rollBack() { if ($this->transactions == 1) { $this->transactions = 0;$this->pdo->rollBack(); } else { --$this->transactions; } }
public function commit() { if ($this->transactions == 1) $this->pdo->commit();--$this->transactions; }