【问题标题】:Nested PDO Transaction not rolling all queries back嵌套 PDO 事务不回滚所有查询
【发布时间】:2015-06-25 09:50:10
【问题描述】:

我正试图了解 PDO 事务,以便一次提交一组相当复杂的 MySQL 查询。但是,当我运行事务时,它将提交一个查询而不是另一个查询 - 如果任一查询中存在单个错误,我希望它回滚两个查询并且不对任一表进行更改。

到目前为止: 我的 connect.php 文件:

class DbConnect {
    private $conn;
    function __construct() {        
    }
    /**
     * Establishing database connection
     * @return database connection handler
     */
    function connect() {
        //Where HOST, USER, PASS etc are set
        include_once "./dbconfig.php";

        // Establish the connection
        try {
        $this->conn = new PDO("mysql:host=".HOST.";dbname=".DBNAME, USER, PASS); 
        $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

        return $this->conn;
        } catch (PDOException $e) {
            print "Error!: " . $e->getMessage() . "<br/>";
            die();
        }
    }
}

我试图传递同时 SQL 查询的文件

    public function transaction ($userId, $amount){
        //Creates the PDO connection EDIT: added my DB connection
        $db = new DbConnect();
        $this->conn = $db->connect();

        $con = $this->conn;

            $con->beginTransaction();
            try{
                $sql = "INSERT INTO transactions (id_user, amount) VALUES (?, ?)";
                $trans = $con->prepare($sql);
                $trans->execute([$userId, $amount]);
                //If I purposely create an error here the query above still runs in the database e.g. remove the $amount variable
                $this->updateBalance($userId, $amount);
                $con->commit();
                return true;
            }
            catch (PDOException $e) {
                $con->rollBack();
                throw $e;                    
            }
    }

    private function updateBalance ($userId, $amount){
            $time = time();
            $sql = "UPDATE balance SET balance=balance + ? WHERE user_id = ?";
            $stmt = $this->conn->prepare($sql);
            $stmt->execute([$amount, $userId]);
            $row_count = $stmt->rowCount();
            return $row_count > 0;
        }

以上只是更大更复杂过程的一小部分示例,否则我只需将余额查询与交易放在同一位置,但是我需要将其保存在单独的函数中。有什么想法可以让我进入“全有或全无”提交状态?

【问题讨论】:

  • 问题在于您没有发布的内容,而不是在此示例中。
  • @Hanky 添加了我的 PDO 连接程序 - 这有帮助吗?我已经将我的代码提炼到与上面完全相同 - 并使用 1 个参数传递 updateBalance 函数(以创建错误) - 第一个查询仍然运行

标签: php pdo transactions


【解决方案1】:

首先,您没有检查对第二个函数的调用的返回状态

$this->updateBalance($userId, $amount);

那么即使有错误,你怎么知道有错误呢?

如果你让被调用函数抛出异常而不是返回状态,它应该被调用块 catch() 块捕获,导致 rollback() 而不是 commit()

类似的东西

public function transaction ($userId, $amount){
    //Creates the PDO connection
    $con = $this->conn;

    $con->beginTransaction();
    try{
        $sql = "INSERT INTO transactions (id_user, amount) VALUES (?, ?)";
        $trans = $con->prepare($sql);
        $trans->execute([$userId, $amount]);
        // If I purposely create an error here the 
        // query above still runs in the database 
        // e.g. remove the $amount variable
        $this->updateBalance($userId, $amount);
        $con->commit();
        return true;
    }
    catch (PDOException $e) {
        $con->rollBack();
        throw $e;
        return false;
    }
}

/*
* If this function throws an exception 
* rather than returning a status, then it will
* stop execution of the try block and
* be caught by the calling blocks catch() block
*/
private function updateBalance ($userId, $amount){

    $sql = "UPDATE balance SET balance=balance + ? WHERE user_id = ?";
    $stmt = $this->conn->prepare($sql);
    $res = $stmt->execute([$amount, $userId]);
    if ( ! $res ) {
        throw new Exception('It errored');
    }

}

或者,您可以在连接到数据库后通过设置PDO::ERRMODE_EXCEPTION 使所有 PDO 调用引发异常。

$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

但是,这可能会对 PDO 的错误处理进行重大更改,具体取决于您已经生成了多少代码。

【讨论】:

  • 谢谢@RiggsFolly - 我试过了,但它似乎没有用 - 我已经编辑了我的问题,显示了我的 PDO 连接功能 - 也许这将有助于阐明我做错了什么?
猜你喜欢
  • 1970-01-01
  • 2011-01-26
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
相关资源
最近更新 更多