我正在尝试使用PHP/PDO在MySQL中设置我的第一个事务…
我只是有一个快速的问题,什么是最好的方法来确定是否以前的查询是成功的或不?这是我现在所拥有的,但我宁愿找到一种方法来用if语句测试查询。
这几乎是模拟代码,试图得到一个工作模型。我知道$results并不能有效地测试任何东西是好是坏。我把它放在那里更多的是作为真正交易的占位符。
if ($_POST['groupID'] && is_numeric($_POST['groupID'])) {
$sql = "SET AUTOCOMMIT=0";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$sql = "START TRANSACTION";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$sql = "DELETE FROM users_priveleges WHERE GroupID=:groupID";
$dbs = $dbo->prepare($sql);
$dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$dbs->execute();
try {
$sql = "DELETE FROM groups WHERE GroupID=:groupID LIMIT 1";
$dbs = $dbo->prepare($sql);
$dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$dbs->execute();
$results["error"] = null;
$results["success"] = true;
try {
$sql = "DELETE FROM users WHERE Group=:groupID";
$dbs = $dbo->prepare($sql);
$dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$dbs->execute();
$results["error"] = null;
$results["success"] = true;
$sql = "COMMIT";
$dbs = $dbo->prepare($sql);
$dbs->execute();
}
catch (PDOException $e) {
$sql = "ROLLBACK";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$results["error"] = "Could not delete associated users! $e";
$results["success"] = false;
}
}
catch (PDOException $e)
{
$sql = "ROLLBACK";
$dbs = $dbo->prepare($sql);
$dbs->execute();
$results["error"] = "COULD NOT REMOVE GROUP! $e";
$results["success"] = false;
}
}
注意事项:除非使用修改参数值的过程,否则不要使用bindParam()
因此,use bindValue()
。bindParam()接受参数值作为引用变量。这意味着你不能做$stmt->bindParam(':num', 1, PDO::PARAM_INT);
——它会引发一个错误。此外,PDO有自己的功能来控制事务,您不需要手动执行查询。
我稍微重写了你的代码,以阐明如何使用PDO:
if($_POST['groupID'] && is_numeric($_POST['groupID']))
{
// List the SQL strings that you want to use
$sql['privileges'] = "DELETE FROM users_priveleges WHERE GroupID=:groupID";
$sql['groups'] = "DELETE FROM groups WHERE GroupID=:groupID"; // You don't need LIMIT 1, GroupID should be unique (primary) so it's controlled by the DB
$sql['users'] = "DELETE FROM users WHERE Group=:groupID";
// Start the transaction. PDO turns autocommit mode off depending on the driver, you don't need to implicitly say you want it off
$pdo->beginTransaction();
try
{
// Prepare the statements
foreach($sql as $stmt_name => &$sql_command)
{
$stmt[$stmt_name] = $pdo->prepare($sql_command);
}
// Delete the privileges
$stmt['privileges']->bindValue(':groupID', $_POST['groupID'], PDO::PARAM_INT);
$stmt['privileges']->execute();
// Delete the group
$stmt['groups']->bindValue(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$stmt['groups']->execute();
// Delete the user
$stmt['users']->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT);
$stmt['users']->execute();
$pdo->commit();
}
catch(PDOException $e)
{
$pdo->rollBack();
// Report errors
}
}
我不会准备&执行事务语句。我会使用PDO::beginTransaction(), PDO::commit()和PDO::rollback()。
PDO::prepare()和PDO::execute()如果有错误,则返回FALSE,否则如果setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION),则抛出PDOException。
在异常处理程序中,应该检查PDO::errorInfo()并报告错误的性质。最佳实践是记录原始错误信息,但给用户一个更友好的消息。不要在UI中回显文字错误消息——这会让用户对SQL查询和模式有不恰当的了解。
PDO语句的execute()
成功时返回TRUE,失败时返回FALSE,因此您可以在if语句中测试前一个execute()
的返回值。
$pdo_result = $dbs->execute();
if ($pdo_result) {
// handle success
} else {
// handle failure
// you can get error info with $dbs->errorInfo();
}
也就是说,正如@Bill Kerwin正确指出的那样(在他的回答中,我完全赞成,因为它完全正确),最好使用PDO::beginTransaction()
, PDO::commit()
和PDO::rollback()
。