Php 如果另一个代码块失败,PDO将回滚

Php 如果另一个代码块失败,PDO将回滚,php,pdo,Php,Pdo,我正在尝试根据另一个代码块的结果回滚PDO事务。如果DB insert失败,这种方法非常有效,但是如果“其他东西”抛出异常,则不会回滚提交。我做错了什么 PHP版本5.4,数据库为MS SQL <?php try { $dbh = new PDO($dataSource); $dbh->beginTransaction(); $sql = "INSERT INTO $table (f

我正在尝试根据另一个代码块的结果回滚PDO事务。如果DB insert失败,这种方法非常有效,但是如果“其他东西”抛出异常,则不会回滚提交。我做错了什么

PHP版本5.4,数据库为MS SQL

<?php
    try {   
        $dbh = new PDO($dataSource);
        $dbh->beginTransaction();
        $sql = "INSERT INTO $table
                    (field1, field2, etc)
                VALUES
                    (:field1, :field2, :etc)"
        $stmt = $dbh->prepare($sql);
        $stmt->bindParam(':field1', $data["field1"]);
        $stmt->bindParam(':field2', $data["field2"]);
        $stmt->bindParam(':etc', $data["etc"]);
        $stmt->execute();
        $dbh->commit();

        //do some other stuff which can throw an Exception
    } catch (Exception $e) {
        //make sure we have something to roll back
        try { $dbh->rollBack(); } catch (Exception $e2) {}
        $log->logFatal("Error: controller.inc.php: " . $e->getMessage());
    }   
?>

调用
commit()
可以有效地完成前面由
beginTransaction()
开始的打开的事务,因此在调用
commit()
之后,没有剩余的数据库操作可以执行
rollBack()

如果有其他代码要在成功提交后运行,则可以在
If()
块中检查其返回值。如果提交操作本身失败,将返回
FALSE
,因此您可以通过引发另一个异常来阻止邮件操作

try {
  $dbh = new PDO($dataSource);
  $dbh->beginTransaction();
  // etc...
  // etc...

  // Attempt to commit, and do other actions if successful
  if ($pdo->commit()) {
    // Do other actions
    // mail, etc...
  }
  else {
    // Otherwise, throw another exception which your catch {} will handle
    throw new Exception('Transaction was not committed');
  }
} catch (Exception $e) {
  // Docs are unclear on whether rollBack() will throw an error on failure
  // or just return false. It is documented to throw an exception if 
  // no transaction is actually active.
  try { $pdo->rollBack(); } catch (Exception $e2) {}
    // Log your error, either a normal PDO error, or failed commit()...
    $log->logFatal("Error: controller.inc.php: " . $e->getMessage());
  }
}

如果您计划在提交后对任何未来错误执行回滚(),则不能执行提交()。您需要将
commit()
移动到其他内容之后。谢谢!SQL有点生疏了。那么,对于commit()本身来说,没有真正的方法捕获错误是很典型的吗?因为我无法撤销其他代码(发送电子邮件)哦,我甚至比你上次评论后的解决方案更喜欢这个。谢谢