如何检查更新查询是否实际更改了数据库中的数据[重复]

问题描述 投票:0回答:3

要更新帐户,客户必须通过电子邮件链接进行验证。 单击后,SQL 中的值将从 0 设置为 1,并返回成功消息。

如果状态已经是1,应该有一条消息表明帐户已经更新。在我的脚本中,即使状态为零,客户也会收到成功更新的消息,并且不会更新到状态 1。

if (!isset($_GET['token'])){
    echo "Link is missing";
}else{
    $token = $_GET['token'];
    // CHECK IF COLUMN 'verified' HAS VALUE '1'
    $stmt = $conn->prepare("SELECT COUNT(*) FROM database WHERE token = ? AND verified = ?");
    $status = 1;
    $stmt->bind_param("ss", $status, $token);
    $res1 = $stmt->execute();
    if ($res1 > 0){
        echo "Your account is already updated";
    }else{
        // UPDATE COLUMN 'verified' TO VALUE '1'
        $stmt = $conn->prepare("UPDATE database SET verified = ? WHERE token = ?");
        $status = 1;
        $stmt->bind_param("ss", $status, $token);
        $res2 = $stmt->execute();
        if ($res2){
            echo "Account updated successfully";
        } 
    }
}
php mysqli sql-update rows-affected
3个回答
2
投票

您可以使用一个查询和原子操作来完成!

$token = $_GET['token']?? '';
if ($token){
    $stmt = $conn->prepare("UPDATE database SET verified = 1 WHERE token = ? AND verified = 0");
    $stmt->bind_param("s", $token);
    $stmt->execute();
    if ($stmt->affected_rows){
        echo "Account updated successfully";
    }else{
        echo "Your account is already updated Or your token is wrong!";
    }
} else 
    echo "Link is missing";
  • 第一个条件,检查 token 是否不是空字符串。
  • 下一个查询将更新具有指定令牌的行,并将已验证 = 0 更新为已验证 = 1
  • 如果提供的令牌错误或帐户已验证
    $stmt->affected_rows
    将为空!

注意: 您可以使用

$stmt->execute([$token])
代替绑定参数并在 PHP 8.1 中执行


-1
投票

Rob 已经指出了第一个问题,因为

mysqli_stmt::execute
成功时返回 true,失败时返回 false。你要检查的是返回值是否大于0,所以你应该获取结果:

$stmt->bind_result($count);
$stmt->fetch();
if ($count > 0)
    ....

-1
投票

正如 Rob 在评论中提到的,参数是向后的,正如 Alijvhr 所回答的,您可以在单个查询中完成您想要做的事情。另外,行

$res1 = $stmt->execute();
the value of
$res1
只告诉你该语句执行是否没有错误,与结果集的内容无关。在 PHP>=8.1 中,默认情况下 mysqli 将引发错误异常,但在此之前,您需要显式检查每个
query()
/
prepare()
/
execute()
调用,或者调用
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
来设置 mysqli 驱动程序生成错误异常。一旦你让 mysqli 进入异常模式,你就可以取消所有
$res1
/
$res2
/等检查。

但是,假设在这种情况下,您不能在一个查询中完成所有操作,则应该将这些语句包含在事务中,以防止查询之间的其他进程更改行。例如:用户不小心双击了提交。

这看起来像:

if (!isset($_GET['token'])){
    echo "Link is missing";
}else{
    $token = $_GET['token'];
    try {
        $conn->begin_transaction();
        // CHECK IF COLUMN 'verified' HAS VALUE '1', and acquire row lock for update
        $stmt = $conn->prepare("SELECT FOR UPDATE COUNT(*) FROM database WHERE token = ? AND verified = ?");
        $status = 0; // get un-verified rows for lock
        $stmt->bind_param("ss", $token, $status); // fixed param order
        $res1 = $stmt->execute();
        if ($res1 && $stmt->affected_rows < 1) { // fix condition check
            echo "Your account is already updated, or an invalid token was provided.";
        }else{
            // UPDATE COLUMN 'verified' TO VALUE '1'
            $stmt = $conn->prepare("UPDATE database SET verified = ? WHERE token = ?");
            $status = 1;
            $stmt->bind_param("ss", $status, $token);
            $res2 = $stmt->execute();
            if ($res2 && $stmt->affected_rows == 1){
                echo "Account updated successfully";
            } else {
                // either the query caused an error, or updated some number of rows other than 1.
                // mysqli should generate its own exception on error by default in PHP>=8.1, raise one of our own just in case.
                $msg = "Unspecified query error has occurred.";
                echo $msg;
                throw new Exception($msg);
            }
        }
        $conn->commit(); // commit changes
    } catch(mysqli_sql_exception|Exception $e) {
        $conn->rollback(); // roll back changes
        throw $e; // re-throw exception for handling elsewhere
    }
}

By default Mysql operates in "implicit transaction" mode where every statement is wrapped in a transaction, so you don't have to worry about collisions and whatnot, but wrapping more complex sets of statements in a single transaction is an important tool to have in your box.
© www.soinside.com 2019 - 2024. All rights reserved.