PHP PDO MySQL事务代码结构

guy*_*mfl 7 php mysql pdo

我正在尝试使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

N.B*_*.B. 24

一些一般注意事项: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
    }    
}
Run Code Online (Sandbox Code Playgroud)


Bil*_*win 6

我不会准备和执行交易声明.我将使用PDO :: beginTransaction(),PDO :: commit()PDO :: rollback().

如果出现错误,PDO :: prepare()和PDO :: execute()返回FALSE,否则如果你设置了setAttribute(PDO :: ATTR_ERRMODE,PDO :: ERRMODE_EXCEPTION),它们会抛出PDOException .

在异常处理程序中,您应该检查PDO :: errorInfo()并报告错误的性质.最佳做法是记录原始错误信息,但为用户提供更友好的消息.

不要在UI中回显文字错误消息 - 这可以为用户提供有关SQL查询和模式的不恰当的知识.


Tro*_*ott 4

PDO 语句成功时返回 TRUE,失败时返回 FALSE,因此您可以在 if 语句中execute()测试前一个语句的返回值。execute()

$pdo_result = $dbs->execute();
if ($pdo_result) {
    // handle success
} else {
    // handle failure
    // you can get error info with $dbs->errorInfo();
}
Run Code Online (Sandbox Code Playgroud)

也就是说,正如 @Bill Kerwin 正确指出的那样(在他的回答中,我完全赞成,因为它完全正确),最好使用PDO::beginTransaction()PDO::commit()PDO::rollback()