【问题标题】:PDO::commit() success or failurePDO::commit() 成功或失败
【发布时间】:2014-07-14 02:52:24
【问题描述】:

PHP PDO::commit() 文档指出该方法在成功时返回 TRUE,在失败时返回 FALSE。这是指beginTransaction()和commit()之间的语句执行成功还是失败?

例如,来自文档:

$dbh->beginTransaction();
$sql = 'INSERT INTO fruit (name, colour, calories) VALUES (?, ?, ?)';
$sth = $dbh->prepare($sql);

foreach ($fruits as $fruit) {
    $sth->execute([
        $fruit->name,
        $fruit->colour,
        $fruit->calories,
    ]);
}

$dbh->commit();

如果上述任何一个执行失败,commit() 方法是否会由于原子事务的“全有或全无基础”而返回 false?

【问题讨论】:

  • 我真的不记得需要在代码库中提交,您是否尝试过不使用它?
  • 我不确定我是否理解。手动事务的重点是确保多个语句要么全部成功,要么都不成功。
  • 我觉得你想多了。如果在这种情况下失败,那么很可能所有人都会失败,反之亦然。只需在代码中添加适当的错误处理,如果您真的担心失败的原因,只需将其记录下来。我从来没有在服务器端代码中使用过提交,我发现你不太可能这样做。
  • 这是文档中的场景。我将使用手动事务的一个示例是从一个表中删除,然后从另一个表中删除。如果其中一个删除失败,另一个也应该失败。因此,如果第一个成功而第二个失败,则应回滚第一个,否则数据库中的数据将处于“中间”状态。这就是我需要手动交易的原因。
  • 很公平。另一种解决方法是执行每个 $fruit ,如果失败,则删除以前插入的,但我知道这不是“自然的”。

标签: php mysql pdo transactions


【解决方案1】:

返回值基于 pdo::commit 本身,而不是您尝试提交的事务。 当没有事务处于活动状态时它返回 FALSE,但它何时应该返回 TRUE 或 FALSE 并不是很清楚。

事务本身中执行的查询将自行成功或失败。 使用 Mr.Tk 的例子,如果可能,事务将被提交,并且在“try”块中执行查询时没有发生错误,如果在“try”块中确实发生了错误,则回滚。

当只评估“try”块中执行的查询时,我个人会尝试捕获 PDOException 而不是普通的异常。

$dbh->beginTransaction();
try {
    // insert/update query
    $dbh->commit();
} catch (PDOException $e) {
    $dbh->rollBack();
}

【讨论】:

    【解决方案2】:

    关键部分是将 PDO 设置为异常模式,而仅使用 try-catch 进行回滚是不必要的。因此,您的代码是可以的,如果您只想在失败时回滚,则无需更改它,只要您在某处有此行:

    $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); 
    

    如果失败,脚本将被终止,连接关闭,mysql 很乐意为您回滚事务。

    如果您仍想手动回滚,则应该正确执行,而不是像其他答案中所说的那样。确保

    • 您捕获的是 Exception,而不是 PDOException,因为哪个特定异常中止了执行并不重要
    • 您在回滚后重新抛出异常,以便收到问题通知
    • 还有一个表引擎支持事务(即对于 Mysql,它应该是 InnoDB,而不是 MyISAM)。

    此清单取自 my article,您可能会发现它在这方面或许多其他方面也很有用。

    【讨论】:

    • 你真的确定吗?如果我执行了 10 次不同的插入或更新,并且在最后一次 pdo 中引发了异常,那么所有其他 9 句都回滚?
    • 我同意@CarlosGoce:如果没有明确的begin/rollback 处理,它不会回滚。但如@Mr.TK 所述,例外情况将有助于运行rollback。事实上,您甚至没有回答有关commit 的问题:如果您想在出现任何问题时取消之前发送的大量查询,那么事务非常有用。
    • @Yvan 肯定会回滚,因为事务总是会在 连接关闭 时回滚。但我宁愿同意,如果使用得当,try catch 对事务很有用。
    • @YourCommonSense:感谢您编辑您的答案,使其更清晰。虽然我不同意«让回滚自己工作»,因为在某个时候更容易看到回滚并且知道事务在这里结束(否则它没有结束......但是脚本的结束),我同意事实上,抛出多个异常是处理这一切的正确方法,并且需要setAttribute。投票赞成。
    【解决方案3】:

    我一直都是这样:

    $dbh->beginTransaction();
    
    try {
         // insert/update query
    
         $dbh->commit();
    } catch (Exception $e) {
         $dbh->rollBack();
    }
    

    而且总是很有魅力! :)

    所以我认为在您的情况下,如果插入失败,应用程序应该抛出异常并且提交甚至不会触发。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-18
      • 2017-03-12
      • 2017-05-07
      • 1970-01-01
      • 2011-09-30
      • 2015-08-27
      • 1970-01-01
      相关资源
      最近更新 更多