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

时间:2014-11-12 21:50:38

标签: php pdo

我试图根据另一个代码块的结果回滚一个PDO事务。如果DB插入失败但是如果"其他东西"抛出异常,它没有回滚提交。我做错了什么?

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());
    }   
?>

1 个答案:

答案 0 :(得分:1)

调用commit()有效地完成了beginTransaction()之前开始的开放式交易,因此在调用commit()之后,rollBack()没有剩余数据库操作。

如果您希望在成功提交后运行其他代码,则可以在if()块中检查其返回值。如果提交操作本身失败,PDO::commit()将返回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());
  }
}