如何在 PHP 中管理嵌套的数据库事务?

Posted

技术标签:

【中文标题】如何在 PHP 中管理嵌套的数据库事务?【英文标题】:How to manage nested database transactions in PHP? 【发布时间】:2014-11-27 14:56:41 【问题描述】:

我有一个方法 deleteUser(..) 执行一个 mysql 查询并调用另一个方法 logAction(..) 调用另一个 mysql 查询。

在这些方法中处理事务的最佳方式是什么?

示例伪代码:

function deleteUser($userId) 
    $db->execute('BEGIN TRANSACTION');

    $userCount = $db->execute("DELETE FROM users WHERE id=$userId");

    logAction('USER DELETED');

    $db->execute('INSERT INTO ... another action');

    $db->execute('COMMIT');


function logAction($action) 
    $db->execute('BEGIN TRANSACTION');

    $db->execute('INSERT INTO logtable ... ACTION');
    if (error)  
        $db->execute('ROLLBACK');
    

    $db->execute('COMMIT');

如您所见,我从 deleteUser() 方法调用 logAction,并遇到了两次“BEGIN TRANSACTION”。在 deleteUser() 完成之前,方法 logAction() 过早地调用了“COMMIT”。

有没有办法在这种嵌套方法中管理事务?

【问题讨论】:

【参考方案1】:

MySql 不支持嵌套事务。还有

开始一个事务会导致提交任何待处理的事务

http://dev.mysql.com/doc/refman/5.5/en/commit.html

但是您需要在一个事务中执行这些查询或单独执行它们。你坚持在事务中运行你的方法。

function deleteUser($userId) 
    if ($this->notInTransation()) throw new NotInTransactionException('not in transaction');

    $userCount = $db->execute("DELETE FROM users WHERE id=$userId");

    logAction('USER DELETED');

    $db->execute('INSERT INTO ... another action');



function logAction($action) 
    if ($this->notInTransation()) throw new NotInTransactionException('not in transaction');
    $db->execute('INSERT INTO logtable ... ACTION');

这样可以确保您的查询在一个事务中运行。使用这种方法,您应该将 begin、rollback、commit 放在更高的层次结构中,或者将查询放在更低的位置。

附:您可以使用autocommit 变量来检查正在启动的事务。

【讨论】:

以上是关于如何在 PHP 中管理嵌套的数据库事务?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JDBC 3.0 实现对嵌套事务的支持

在 PHP / CodeIgniter 中,不止一个事务开始了,而另一个事务没有完成;比如嵌套事务

java 事务

php 事务处理transaction

PHP PDO 事务与自动提交

如何避免嵌套事务不支持错误?