Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 存在事务时如何处理错误?_Php_Mysql_Pdo - Fatal编程技术网

Php 存在事务时如何处理错误?

Php 存在事务时如何处理错误?,php,mysql,pdo,Php,Mysql,Pdo,这是我的密码: 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 WH

这是我的密码:

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

如您所见,当出现异常时,我的脚本将回滚所有查询。但是当($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()的调用也是多余的,可以删除。

请参阅抛出一个异常将您的修改从try catchError中删除。

在此
$\u会话中['error']
将包含
一些错误
,而不是
令牌无效
。然后只需删除
$\u会话['error']='token is invalid';
然后抛出你的异常为什么?我需要三条错误消息。
一切正常,
令牌无效,
有问题。
。!抛出异常只允许我有两条错误消息。而我需要处理三条错误消息。我严格不建议在中使用general\exception在这种情况下,更可能创建您自己的异常,例如DatabaseProblemException。因为在这种情况下,当您尝试捕获所有类型的异常时,您不会得到任何日志信息,您只需在代码中隐藏您希望得到的其他错误。例如,如果您的表名中有打字错误,而不是明显的错误r消息“表激活\u账户不存在”,您将看到“出现问题”。这将花费您时间来找出原因。我更新了答案,以允许您有两条不同的错误消息。另一种方法是检查异常类型并以这种方式调整您的消息。您的方法仅适用于我的问题中的示例。实际上,我的代码更复杂,您的方法没有用处。抱歉buddy..+因为这个答案适用于上述示例。@stack不需要道歉!我只是想帮你。你太好了。你的方法只适用于我问题中的示例。事实上,我的代码更复杂,你的方法没有用。显然,我们只能根据你的问题得出答案我们无法改变你的真实密码。这种性质的问题是吸引反对票和接近票的磁铁。你是对的。但我的密码实际上非常庞大,难以理解(甚至难以阅读).这就是我简化它的原因..是的,但是说这不起作用,因为这不是我真正的代码是在浪费每个人的时间..+对于这个答案,因为它适用于所提到的示例。