【问题标题】:My PDO transaction doesn't commit, but also doesn't throw any exception我的 PDO 事务没有提交,但也没有抛出任何异常
【发布时间】:2014-12-31 00:06:15
【问题描述】:

到目前为止,我有一些查询运行良好,但我想将它们包装在事务中以减少数据损坏的可能性。运行代码后,一切似乎都可以工作(即没有抛出异常),但查询永远不会提交到数据库。我看过关于 S.O. 的其他问题。但我还没有发现任何适用于我的案例。

这是我的代码:

    db::$pdo->beginTransaction();  // accesses PDO object method

    try {

        $sql = "INSERT INTO expenses SET date=:date, amount=:amount, accountId=:account; ";

        $sql .= "UPDATE accounts SET balance = balance - :amount WHERE id = :account";


        $s = db::$pdo->prepare($sql);
        $s->bindValue(':date', $date);
        $s->bindValue(':amount', $amount);
        $s->bindValue(':account', $account);

        $s->execute();

        db::$pdo->commit();
        echo 'success';
    }
    catch (PDOException $e) {
        db::$pdo->rollback();
        echo '<p>Failed: ' . $e->getMessage() . '</p>';
    }

当我运行代码时,它会输出成功消息,但就像我说的,没有任何东西被提交到数据库。

由于它是相关的,我还应该注意我的 PDO 错误模式设置为ERRMODE_EXCEPTION,所以我认为这不是导致问题的原因。我正在运行 MySQL 数据库 (InnoDB)

有什么想法吗?

【问题讨论】:

  • 只是在黑暗中试一试,但请尝试单独运行查询,看看是否有效。

标签: php mysql pdo


【解决方案1】:

我不完全确定在单个查询语句中运行多个查询是如何工作的(如果可以的话),因为我通常通过在准备/执行语句中单独运行每个查询来执行事务。该事务仍将所有更改排队,直到按预期提交/回滚。根据this SO answer,它似乎可以工作,但是该示例不是绑定值,因此这可能是另一个问题。

我建议将查询拆分为多个准备/绑定/执行语句,它应该可以按预期工作。

【讨论】:

  • 这成功了。在单个语句中运行多个查询可以正常工作,除非您将它们包装在事务中,在这种情况下,事务由于某种原因不会被提交。将它们拆分为单独的准备/执行语句非常有效。
  • 在单个语句中运行多个查询只有在您使用模拟的预准备语句而不是正确的预准备语句时才能“正常”工作。你真的应该disable this
  • @PeeHaa 我在链接的答案中看到了这一点。据此,虽然它默认情况下是打开的。 OP 没有禁用它们(至少不是在这里),所以我认为它们的代码应该可以工作,就像链接答案中的第二个示例一样。
  • 我的意思是 OP 应该改变它,因为默认值很糟糕。使用模拟的预处理语句为可能的安全漏洞打开了大门。
  • @PeeHaa 同意,但我只是想知道它是否/为什么不起作用。但我想如果你认为这很糟糕并且不应该那样使用的话,这一点就没有实际意义了。
【解决方案2】:

总是会显示成功消息,因为它只是用来回显.. 如果您只想在执行后显示成功,您应该使用 if 语句.. 对于未提交的部分,它可能是很多事情.. 你确定正在提供所有值 $date、$amount、$account 吗?您也可以尝试从简单的插入开始,如果可行,请进行更新..

$sql = 'INSERT INTO expenses (date, amount, account)
                    VALUES(:date, :amount, :account)';

    $stmt = $this->pdo->prepare($sql);

    $stmt->bindValue(':date', $);
    $stmt->bindValue(':amount', $amount);
    $stmt->bindValue(':account', $account);

        if($stmt->execute()) {
            db::$pdo->commit();
            echo 'success';
        }    

不确定 db::$pdo->commit();部分是因为我使用某种 OOP 方式,但希望这可能会有所帮助。

【讨论】:

  • 如果插入成功但更新失败,则插入然后更新会导致数据损坏。这就是交易的全部目的
【解决方案3】:

我认为我在其中一个项目中遇到了类似的问题,请在您拥有的那个之后添加另一个 catch 块,这样代码将如下所示:

catch (PDOException $e) {
        db::$pdo->rollback();
        echo '<p>Failed: ' . $e->getMessage() . '</p>';
    }
catch (Exception $exc) {
         db::$pdo->rollback();
         echo '<p>Failed: ' . $exc->getMessage() . '</p>';
}

它将允许您捕获除PDOException 以外的类的异常,因此您可以确保更多。

更新:

请考虑将两个查询拆分为 2 个 PDO 语句,如下所示:

$sql = "INSERT INTO expenses SET date=:date, amount=:amount, accountId=:account; ";

$s = db::$pdo->prepare($sql);
$s->bindValue(':date', $date);
$s->bindValue(':amount', $amount);
$s->bindValue(':account', $account);

$s->execute();

$sql2 = "UPDATE accounts SET balance = balance - :amount WHERE id = :account;";

$s2 = db::$pdo->prepare($sql2);
$s2->bindValue(':amount', $amount);
$s2->bindValue(':account', $account);

$s2->execute();

我在整个项目中成功地使用了这种方法,所以我希望它可能会有所帮助。

【讨论】:

  • 如果存在 PDO 以外的异常,它仍应抛出错误(并且不会回显“成功”消息)。不过我试过了,还是没有运气。
【解决方案4】:

不要使用db::$pdo-&gt;commit();

使用

$sql = "INSERT INTO expenses SET date=:date, amount=:amount, accountId=:account;";

$sql .= "UPDATE accounts SET balance = balance - :amount WHERE id = :account;COMMIT;";  // change here

有点傻 ;(

【讨论】:

  • 这表明您的数据库库中存在错误 - 如果提交调用未转换为数据库提交,则会出现严重错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多