这篇文章主要介绍了PHP中实现MySQL嵌套事务的两种解决方案,本文分析了doctrine和laravel的实现方式,并提取出来分析和总结,需要的朋友可以参考下
一、问题起源
在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。接下来我们就一起来看下这两个框架是怎样来实现的。
友情提示,这两个框架的函数和变量的命名都比较的直观,虽然看起来很长,但是都是通过命名就能直接得知这个函数或者变量的意思,所以不要一看到那么一大坨就被吓到了 :)
二、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; }
算了,不费口舌解释这段了吧 :)
三、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; }
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
如何PHP中Laravel框架实现supervisor执行异步进程
以上是如何实现PHP中MySQL嵌套事务的详细内容。更多信息请关注PHP中文网其他相关文章!

DependencyInjection(DI)inPHPenhancescodeflexibilityandtestabilitybydecouplingdependencycreationfromusage.ToimplementDIeffectively:1)UseDIcontainersjudiciouslytoavoidover-engineering.2)Avoidconstructoroverloadbylimitingdependenciestothreeorfour.3)Adhe

到Improveyourphpwebsite的实力,UsEthestertate:1)emplastOpCodeCachingWithOpcachetCachetOspeedUpScriptInterpretation.2)优化的atabasequesquesquesquelies berselectingOnlynlynnellynnessaryfields.3)usecachingsystemssslikeremememememcachedisemcachedtoredtoredtoredsatabaseloadch.4)

是的,itispossibletosendMassemailswithp.1)uselibrarieslikeLikePhpMailerorSwiftMailerForeffitedEmailSending.2)enasledeLaysBetemailStoavoidSpamflagssspamflags.3)sylectynamicContentToimpovereveragement.4)

DependencyInjection(DI)inPHPisadesignpatternthatachievesInversionofControl(IoC)byallowingdependenciestobeinjectedintoclasses,enhancingmodularity,testability,andflexibility.DIdecouplesclassesfromspecificimplementations,makingcodemoremanageableandadapt

使用PHP发送电子邮件的最佳方法包括:1.使用PHP的mail()函数进行基本发送;2.使用PHPMailer库发送更复杂的HTML邮件;3.使用SendGrid等事务性邮件服务提高可靠性和分析能力。通过这些方法,可以确保邮件不仅到达收件箱,还能吸引收件人。

计算PHP多维数组的元素总数可以使用递归或迭代方法。1.递归方法通过遍历数组并递归处理嵌套数组来计数。2.迭代方法使用栈来模拟递归,避免深度问题。3.array_walk_recursive函数也能实现,但需手动计数。

在PHP中,do-while循环的特点是保证循环体至少执行一次,然后再根据条件决定是否继续循环。1)它在条件检查之前执行循环体,适合需要确保操作至少执行一次的场景,如用户输入验证和菜单系统。2)然而,do-while循环的语法可能导致新手困惑,且可能增加不必要的性能开销。

在PHP中高效地哈希字符串可以使用以下方法:1.使用md5函数进行快速哈希,但不适合密码存储。2.使用sha256函数提高安全性。3.使用password_hash函数处理密码,提供最高安全性和便捷性。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

记事本++7.3.1
好用且免费的代码编辑器

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。