当前位置: 首页 > 编程笔记 >

PHP中实现MySQL嵌套事务的两种解决方案

濮阳烨然
2023-03-14
本文向大家介绍PHP中实现MySQL嵌套事务的两种解决方案,包括了PHP中实现MySQL嵌套事务的两种解决方案的使用技巧和注意事项,需要的朋友参考一下

一、问题起源

在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实现mysql事务处理的方法,包括了php实现mysql事务处理的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了php实现mysql事务处理的方法。分享给大家供大家参考。具体分析如下: 要实现本功能的条件是环境 mysql 5.2 /php 5 支持事务的table 类型,需要InnoDB,有了这些条件你就可以做上面的实现了,这个事物回滚操作是大项目经常用到的,像

  • 问题内容: MySQL是否允许使用嵌套事务? 问题答案: 支持。 您可以执行以下操作:

  • 本文向大家介绍window.onload绑定多个事件的两种解决方案,包括了window.onload绑定多个事件的两种解决方案的使用技巧和注意事项,需要的朋友参考一下 前言 有些函数,必须在网页加载完毕后执行。比如:涉及DOM操作的。 网页加载完毕时会触发一个onload事件,将函数绑定到这个事件上即可。 问题来了:如果需要同时绑定多个事件,该如何处理呢?有两种解决方法 方案一 创建一个匿名函数,

  • 问题内容: 我正在研究应用数据库架构更新的脚本。我已经使用start transaction / commit设置了所有的SQL更新脚本。我在命令行上将这些脚本传递给psql。 现在,我需要在一个事务中同时应用多个脚本。到目前为止,我想出的唯一解决方案是从原始脚本集中删除启动事务/提交,然后将它们卡在新的启动事务/提交块中。我正在编写perl脚本来即时执行此操作。 实际上,我想要嵌套事务,但是我无

  • 本文向大家介绍详解PHP实现定时任务的五种方法,包括了详解PHP实现定时任务的五种方法的使用技巧和注意事项,需要的朋友参考一下 定时运行任务对于一个网站来说,是一个比较重要的任务,比如定时发布文档,定时清理垃圾信息等,现在的网站大多数都是采用PHP动态语言开发的,而对于PHP的实现决定了它没有Java和.Net这种AppServer的概念,而http协议是一个无状态的协议,PHP只能被用户触发,被

  • 本文向大家介绍PHP使用Mysql事务实例解析,包括了PHP使用Mysql事务实例解析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲解了PHP使用MySQL事物的实例,并备有注释加以详细说明。分享给大家供大家参考之用。 具体实例如下所示: 希望本文所述实例对大家PHP+MySQL程序设计的学习有所帮助。