繁体   English   中英

有交易时如何处理错误?

[英]How can I handle errors when there is transaction?

这是我的代码:

try {
    $dbh_con->beginTransaction();

        $stmt1 = $dbh_conn->prepare("UPDATE activate_account_num SET num = num + 1");
        $stmt1->execute();

        $stmt2 = $dbh_con->prepare("SELECT user_id FROM activate_account WHERE token = ?");
        $stmt2->execute(array($token));
        $num_rows = $stmt2->fetch(PDO::FETCH_ASSOC);

        if ( $num_rows['user_id'] ){
            $_SESSION['error'] = 'all fine';

        } else {
            $_SESSION['error'] = 'token is invalid';
        }

    $dbh_con->commit();

    header('Location: /b.php');
    exit();

} catch(PDOException $e) {

    $dbh_con->rollBack();

    $_SESSION['error'] = 'something is wrong';
    header('Location: /b.php');
    exit();
}

如您所见,当出现异常时,我的脚本会回滚所有查询。 但是, if ( $num_rows['user_id'] ){false ,则不会回滚。 那么,当条件为false时,我如何既可以回滚查询并保持错误'token is invalid'呢?

只需抛出一个异常并像您已经捕获的那样捕获它即可。 但是除了两个catch语句,还有两个:

try {
    $dbh_con->beginTransaction();

        $stmt1 = $dbh_conn->prepare("UPDATE activate_account_num SET num = num + 1");
        $stmt1->execute();

        $stmt2 = $dbh_con->prepare("SELECT user_id FROM activate_account WHERE token = ?");
        $stmt2->execute(array($token));
        $num_rows = $stmt2->fetch(PDO::FETCH_ASSOC);

        if ( $num_rows['user_id'] ){
            $_SESSION['error'] = 'all fine';

        } else {
            throw new \Exception('token is invalid');
        }

    $dbh_con->commit();

    header('Location: /b.php');
    exit();

} catch(PDOException $e) {

$dbh_con->rollBack();

$_SESSION['error'] = 'something is wrong';
header('Location: /b.php');
exit();
} catch(Exception $e) {

    $dbh_con->rollBack();

    $_SESSION['error'] = 'token is invalid';
    header('Location: /b.php');
    exit();
}

您的操作顺序不好。 在验证令牌之前,您正在数据库中进行更改。 这是不良的安全设计。 始终首先验证所有输入,然后才进行更改。

其次,获取令牌的SELECT查询不需要成为事务的一部分。 回滚SELECT没有影响,因为这样的查询不会更改数据库。 所以我会做

try{
   select token
   if token is not found, set error and exit

   begin transaction
   update active_account_num
   ...other queries?
   end transaction and commit

   set success message, set header & exit
}catch{
   rollback
   set error message, set header & exit
}

在这种情况下,因为只有一个查询可以更改数据库,所以您甚至不需要事务。

如果您在确保表中包含感兴趣的值之后进行更新,则容易得多

try {
    $stmt2 = $dbh_con->prepare("SELECT user_id FROM activate_account WHERE token = ?");
    $stmt2->execute(array($token));
    $num_rows = $stmt2->fetch(PDO::FETCH_ASSOC);

    if ( $num_rows['user_id'] ){
        $dbh_con->beginTransaction();
        $stmt1 = $dbh_conn->prepare("UPDATE activate_account_num SET num = num + 1");
        $stmt1->execute();

        $_SESSION['error'] = 'all fine';
        $dbh_con->commit();

    } else {
        $_SESSION['error'] = 'token is invalid';
        /* no transaction here, nothing to rollback */
    }

    header('Location: /b.php');
    exit();

} catch(PDOException $e) {

    $dbh_con->rollBack();

    $_SESSION['error'] = 'something is wrong';
    header('Location: /b.php');
    exit();
}

对exit()的调用也是多余的,可以删除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM