PHP中完成MySQL嵌套事務的兩種處理計劃。本站提示廣大學習愛好者:(PHP中完成MySQL嵌套事務的兩種處理計劃)文章只能為提供參考,不一定能成為您想要的結果。以下是PHP中完成MySQL嵌套事務的兩種處理計劃正文
1、成績來源
在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.
然則在我們開辟一個龐雜的體系時不免會有意中在事務中嵌套了事務,好比A函數挪用了B函數,A函數應用了事務,而且是在事務中挪用了B函數,B函數也有一個事務,如許就湧現了事務嵌套。這時候候其實A的事務就意義不年夜了,為何呢?下面的文檔中就有提到,簡略的翻譯過去就是:
當履行一個START TRANSACTION指令時,會隱式的履行一個commit操作。
所以我們就要在體系架構層面來支撐事務的嵌套。所幸的是在一些成熟的ORM框架中都做了對嵌套的支撐,好比doctrine或許laravel。接上去我們就一路來看下這兩個框架是如何來完成的。
友誼提醒,這兩個框架的函數和變量的定名都比擬的直不雅,固然看起來很長,然則都是經由過程定名就可以直接得知這個函數或許變量的意思,所以不要一看到那末一年夜坨就被嚇到了 :)
2、doctrine的處理計劃
起首來看下在doctrine中創立事務的代碼(干失落了不相干的代碼):
public function beginTransaction()
{
++$this->_transactionNestingLevel;
if ($this->_transactionNestingLevel == 1) {
$this->_conn->beginTransaction();
} else if ($this->_nestTransactionsWithSavepoints) {
$this->createSavepoint($this->_getNestedTransactionSavePointName());
}
}
這個函數的第一行用一個_transactionNestingLevel來標識以後嵌套的級別,假如是1,也就是還沒有嵌套,那就用默許的辦法履行一下START TRANSACTION就ok了,假如年夜於1,也就是有嵌套的時刻,她會幫我們創立一個savepoint,這個savepoint可以懂得為一個事務記載點,當須要回滾時可以只回滾到這個點。
然後看下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;
}
}
可以看隨處理的方法也很簡略,假如level是1,直接rollback,不然就回滾到後面的savepoint。
然後我們持續看下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;
}
算了,不費口舌說明這段了吧 :)
3、laravel的處理計劃
laravel的處置方法絕對簡略粗魯一些,我們先來看下創立事務的操作:
public function beginTransaction()
{
++$this->transactions;
if ($this->transactions == 1)
{
$this->pdo->beginTransaction();
}
}
感到若何?so easy吧?先斷定以後有幾個事務,假如是第一個,ok,事務開端,不然就啥都不做,那末為啥是啥都不做呢?持續往下看rollBack的操作:
public function rollBack()
{
if ($this->transactions == 1)
{
$this->transactions = 0;
$this->pdo->rollBack();
}
else
{
--$this->transactions;
}
}
明確了吧?只要铛铛前事務只要一個的時刻才會真實的rollback,不然只是將計數做減一操作。這也就是為啥適才說laravel的處置比擬簡略粗魯一些,在嵌套的內層外面現實上是木有真實的事務的,只要最外層一個全體的事務,固然簡略粗魯,然則也處理了在內層新建一個事務時會形成commit的成績。道理就是這個模樣了,為了堅持完全起見,把commit的代碼也copy過去吧!
public function commit()
{
if ($this->transactions == 1) $this->pdo->commit();
--$this->transactions;
}