PHP PDO MySQL Transaction code structure

怎甘沉沦 提交于 2019-12-31 09:05:21

问题


I am trying to set up my first transaction in MySQL using PHP/PDO...

I just have a quick question, what is the best way to determine if the previous query was successful or not? Here is what I have right now, but I would rather find a way to test the query with an if statement.

This is pretty much mock up code to try to get a working model.. I know $results isn't effectively testing if anything was good or bad.. i have it there more as a place holder for the real deal when the time comes..

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;
    }
}

回答1:


Some general notes: Don't use bindParam() unless you use a procedure that modifies the parameter's value Therefore, use bindValue(). bindParam() accepts argument value as a referenced variable. That means you can't do $stmt->bindParam(':num', 1, PDO::PARAM_INT); - it raises an error. Also, PDO has its own functions for controlling transactions, you don't need to execute queries manually.

I rewrote your code slightly to shed some light on how PDO can be used:

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
    }    
}



回答2:


I wouldn't prepare & execute the transaction statements. I'd use PDO::beginTransaction() , PDO::commit(), and PDO::rollback().

PDO::prepare() and PDO::execute() return FALSE if there's an error, or else they throw PDOException if you setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION).

In your exception handler, you should check PDO::errorInfo() and report the nature of the error. Best practice is to log the raw error info, but give the user a more friendly message.

Don't echo the literal error message in the UI -- this can give the user inappropriate knowledge about your SQL query and schema.




回答3:


PDO Statement's execute() returns TRUE on success and FALSE on failure, so you can test the return value of the previous execute() in your if statement.

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

That said, as @Bill Kerwin correctly points out (in his answer that I'm totally upvoting because it's exactly correct), it would be preferable to use PDO::beginTransaction(), PDO::commit(), and PDO::rollback().



来源:https://stackoverflow.com/questions/8618618/php-pdo-mysql-transaction-code-structure

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!