【问题标题】:PDO inTransaction() returning false after database exception数据库异常后 PDO inTransaction() 返回 false
【发布时间】:2016-10-23 11:56:45
【问题描述】:

如果引发数据库异常,PDO 的 inTransaction() 在仍在事务中时返回 false。这可能特定于使用 PostgreSQL。例如

try {
    $pdo->beginTransaction();
    $pdo->exec('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
    // ...
    // Cause any PDO exception
    // ...
    $pdo->commit();
} catch (\Exception $e) {
    if ($pdo->inTransaction()) {
        // Never gets here
        $pdo->rollback();
    }
    throw $e;
}

事务肯定没有结束,因为如果我开始另一个事务,我会得到一个异常,表明事务已经在进行中。我还没有测试过所有类型的异常,但是SQLSTATE[40001]: Serialization failure 和主键违规肯定会发生这种情况。 这是预期的行为还是 PHP 中的错误?

似乎知道回滚的唯一方法是保留一个单独的变量来知道我在事务中,使inTransaction() 无用。我注意到一些开源框架(如Doctrine)和应用程序(如Drupal)为事务状态保留了自己的变量。 为什么我们不能依靠驱动程序或数据库来告诉我们事务是否正在进行?

PHP 5.5.32 和 PostgreSQL 9.4。找到了一个两年前的相关bug report,它在旧版本的 PHP 中已关闭。

【问题讨论】:

标签: php postgresql pdo transactions


【解决方案1】:

回答你的问题:

这是预期的行为还是 PHP 中的错误?

不,这不是预期的行为,必须是 PDO PgSQL 扩展中的错误。

为什么我们不能依靠驱动程序或数据库来告诉我们是否存在 交易正在进行中?

因为驱动程序和数据库是由人类创建的。在创建数据库或驱动程序等高度复杂的应用程序时,人类可能会犯错误。对我来说,您的问题看起来不是边缘情况,也可能在任何数据库中导致严重的完整性问题。您可能还想考虑在 php bug 跟踪器上打开一个代码。

补丁代码分析

但是我对它进行了更多研究。比较 2 年前补丁中的代码 (source) 和当前代码 1 (source) 表明,自从他们修补了该错误以来,没有任何变化。至少在那些直接受影响的功能中没有,而且当时它也可能是一个稍微不同的错误。所以我的猜测是,还有一些其他的东西当然不能帮助你解决问题。

解决当前问题的可能方法m:

您可以检查您的连接是否有未完成的交易。为此,您需要在遇到异常时创建第二个连接。首先确定您当前的连接 ID。

SELECT pg_backend_pid();

在我的例子中,它返回了数字19339。您应该在启动将导致异常的查询之前保存此数字。 现在在您的 catch 块中,您需要查看表 pg_catalog.pg_stat_activity 的内部。

查找旧连接,看看它的状态是否为

activeidle in transactionidle in transaction (aborted)

与:

SELECT state FROM pg_catalog.pg_stat_activity WHERE pid=19339;

如果它返回idle,则该旧连接没有当前事务。如果它是前三个之一,则交易仍然处于活动状态。 postgresql 的手册说:

active: The backend is executing a query.
idle: The backend is waiting for a new client command.
idle in transaction: The backend is in a transaction, but is not currently executing a query.
idle in transaction (aborted): This state is similar to idle in transaction, except one of the statements in the transaction caused an error.
fastpath function call: The backend is executing a fast-path function.
disabled: This state is reported if track_activities is disabled in this backend.

最后一个状态表明了这一切的不利因素。 仅当track_activities 配置标志设置为true 时它才会起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多