mysqli_query 返回 0 行(奇怪的行为)

Posted

技术标签:

【中文标题】mysqli_query 返回 0 行(奇怪的行为)【英文标题】:mysqli_query returns 0 rows (weird behaviour) 【发布时间】:2013-07-04 16:46:11 【问题描述】:

这个非常简单的方法是从 Flash Actionscript 应用程序调用的,旨在仅删除一条记录。 这是一个非常大的应用程序,包含 1,000 多个脚本,其中许多成功地使用了相同的架构......但是这个拒绝像其他人一样行事。

为了简单起见,我已经清理了部分代码,对此毫无意义 正如我之前所说,它非常简单(正如您在代码中看到的那样):

    检查记录是否存在。 启动 mysql 事务(START TRANSACTION) 删除所需记录 删除/更新一些其他相关信息(本代码省略) 如果一切正常,则提交事务

问题如下:

如果我按照代码所示运行脚本,在第一个 SELECT 语句 ($query1) 之后,mysqli_num_rows($result1) 返回 0(零)条记录,尽管我可以在数据库中看到该记录存在。既然如此,显然不能删除,跳到脚本的末尾。但是,(这是最奇怪的行为!!!)记录实际上已被删除。 如果我注释 COMMIT 语句 ($query5),mysqli_num_rows($result1) 返回 1(一)。这应该没问题,DELETE 语句运行正常($query4),但由于 COMMIT 已被注释,事务没有正确完成,所需的记录当然保留在数据库中。 如果我注释 SELECT 语句 ($query1) 并直接执行 DELETE 语句 ($query4),而不检查记录是否存在,则记录被正确删除,最后一个 COMMIT 语句 ($query5) 确认数据库更改。

我已经逐步跟踪了几个小时,但到目前为止,找不到此代码无法正常运行的原因 我还用 mysqli_affected_rows 替换了 mysqli_num_rows(为了 SELECT 语句的目的是相同的),但奇怪的行为仍然存在。

<?php
function f_ROLLBACK() 
    global $messages;
    global $conexion;
    $query  = "";
    $query .= "ROLLBACK";
    $result = mysqli_query( $conexion, $query);
    if (!$result === true) 
        $messages .= "\nInvalid Query\n".mysqli_error( $conexion )."\nQUERY:".$query;
     else 
        $messages .= "\nTransaction successful ROLLBACK";
    //if (!$result === true)
    return;
//function f_ROLLBACK

include ("../config/DBconfig.inc.php");

$recID = isset($_POST["recID"]) ? $_POST["recID"] : "5";

$returnVars = array();
$messages = "";
$n = 0;
$now = gmdate("YmdHis");

//check if exists
$query1  = "";
$query1 .= "SELECT recID ";
$query1 .= "    FROM records ";
$query1 .= " WHERE recID = ".$recID." ";

$result1 = mysqli_query( $conexion, $query1);

if (!$result1 === true) 
    $messages .= "\nInvalid Query\n".mysqli_error( $conexion )."\nQUERY1:".$query1;
 else 
    $rows1 = mysqli_num_rows($result1);
    if ($rows1 < 1) 
        $messages .= "\nSelected Record could not be found.";
     else 

        $query2  = "";
        $query2 .= "START TRANSACTION";

        $result2 = mysqli_query( $conexion, $query2);

        if (!$result2 === true) 
            $messages .= "\nInvalid Query\n".mysqli_error( $conexion )."\nQUERY2:".$query2;
         else 

            $query3  = "";
            $query3 .= "SET autocommit = 0 ";

            $result3 = mysqli_query( $conexion, $query3);

            if (!$result3 === true) 
                $messages .= "\nInvalid Query\n".mysqli_error( $conexion )."\nQUERY3:".$query3;
                f_RollBack();
             else 

                $query4  = "";
                $query4 .= "DELETE FROM records ";
                $query4 .= " WHERE recID = ".$recID."   ";

                $result4 = mysqli_query( $conexion, $query4);

                if (!$result4 === true) 
                    $messages .= "\nInvalid Query\n".mysqli_error( $conexion )."\nQUERY4:".$query4;
                    f_RollBack();
                 else 

                    $rows4 = mysqli_affected_rows($GLOBALS["___mysqli_ston"]);

                    if ($rows4 < 1) 
                        $messages .= "\nSelected Record could not be DELETED.\nQUERY4:".$query4;;
                        f_RollBack();
                     else 

                        $query5  = "";
                        $query5 .= " COMMIT ";

                        $result5 = mysqli_query( $conexion, $query5);

                        if (!$result5 === true) 
                            $messages .= "\nInvalid Query\n".mysqli_error( $conexion )."\nTransaction has not been COMITTED."."\nQUERY5:".$query5;
                        //if (!$result5 === true) COMMIT
                    //if ($rows4 == -1) 
                //if (!$result4 === true)
            //if ($rows3 < 1)
        //if (!$result3 === true)
    //if (!$result2 === true)
//if (!$result1 === true)


mysqli_close($GLOBALS["___mysqli_ston"]);

if ($messages != "") 
    $returnVars["retorno"]  = "Error";
    $returnVars["extra"]        = $messages;
 else 
    $returnVars["retorno"]  = "OK";
    $returnVars["extra"]        = "";
//if ($messages != "")

$returnString = http_build_query($returnVars);

//send variables back to Flash
echo $returnString;
 ?>

如果有人能找出我做错了什么,我将不胜感激。

【问题讨论】:

首先,我没有完整阅读这个问题。但引起我注意的是$query1 .= " WHERE recID = ".$recID." ";。尝试将其替换为 $query1.= " WHERE recID = '".$recID."' "; 您在桌子底部之外使用ENGINE = INNODB 吗?您需要使用该引擎进行交易。 @Muhammed:感谢您的评论,但 recID 是该表中的主键,INT(11),AUTONUM。 @Jason:感谢您的评论。是的,表和数据库都是 INNODB。在所有其他脚本中,事务正在根据需要正确处理、提交或回滚 如果上述脚本被调用两次,并且您正在调试的调用(即产生您描述的结果的调用)是第二次调用,则上述所有症状都将成立。表明这一点的关键是If I run the script as shown in the code, after the first SELECT statmente ($query1), mysqli_num_rows($result1) returns 0 (zero) records although [...] the record is being actually DELETED - 这显然是不可能的。 【参考方案1】:

我之前提供过这个并且被否决了。我认为这个框架可能会对你有所帮助,所以我会再次冒险。哈哈。请注意,我希望它通过提供一种简单的调试方法来帮助您解决问题(只需将 false 更改为 true ...并且调试已开启!)。

本系统的使用方法是将设置信息(#Sample Execution 之前的所有内容)放在页面顶部,将#functions 放在页面底部......然后有几个例子说明如何“使用”这两个函数从该点向前通过两行(一行定义查询,一行运行查询)获取数据。结果是数据库中的更改或包含您请求的数据的数组。希望能帮助到你。我们每天都在使用它。

define('DEBUG', false);
define('CLIDISPLAY', false);
if (CLIDISPLAY) 
    define('PRE', '');
    define('PRE_END', '');
 else 
    define('PRE', '<pre>');
    define('PRE_END', '</pre>');

require_once("../dbconnect.php");
$DBLink = new mysqli($VARDB_server, $VARDB_user, $VARDB_pass, $VARDB_database, $VARDB_port);
if ($DBLink->connect_errno) 
    printf(PRE . "Connect failed: %s\n" . PRE_END, $DBLink->connect_error);
    exit();


# Sample execution
$Query = "select * from vicidial_users where user='6666' and active='Y' limit 1";
$Records = GetData($DBLink, $Query);
print_r($Records[0]); // Single record return access via [0] to access a field named "id": $Records[0]['id']
// Multiple record return access via array walking
foreach ($Records as $Record) 
    print_r($Record);

$Query = "update vicidial_users set active='Y' where user='6666' limit 1";
UpdateData($DBLink, $Query);

#Functions

function GetData($DBLink, $Query) 
    if (DEBUG) 
        echo PRE . "Query: $Query\n" . PRE_END;
    
    if ($Result = $DBLink->query($Query)) 
        if (DEBUG) 
            printf(PRE . "Affected rows (Non-Select): %d\n" . PRE_END, $DBLink->affected_rows);
        
        while ($Record = $Result->fetch_assoc()) 
            $ReturnData[] = $Record;
        
        return $ReturnData;
     else 
        if (DEBUG) 
            printf(PRE . "Errormessage: %s\n", $DBLink->error);
            printf("Affected rows (Non-Select): %d\n", $DBLink->affected_rows);
            echo "No Records Returned\n" . PRE_END;
        
        return false;
    


function UpdateData($DBLink, $Query) 
    if (DEBUG) 
        echo PRE . "Query: $Query\n" . PRE_END;
    
    if ($Result = $DBLink->query($Query)) 
        if (DEBUG) 
            printf(PRE . "%s\n", $DBLink->info);
            printf("Affected rows (Non-Select): %d\n" . PRE_END, $DBLink->affected_rows);
        
        return;
     else 
        if (DEBUG) 
            printf(PRE . "Errormessage: %s\n", $DBLink->error);
            printf("Affected rows (Non-Select): %d\n", $DBLink->affected_rows);
            echo "No Records Returned\n" . PRE_END;
        
        return;
    

显然 dbconnect.php 及其加载的变量可以替换为您现有的版本。要进行故障排除:将调试更改为 TRUE 而不是 FALSE。然后查询将溢出到屏幕上,您可以将其直接复制/粘贴到您的数据库中,看看结果是否符合预期。请注意,为了获得最佳结果,您仍然需要在执行此操作时验证一些项目(其中一些仅当您运行相同查询时 php 脚本得到与您不同的结果时才需要):

    确保您位于正在加载到您的凭据中的数据库中 确保您以与正在运行的脚本相同的用户身份使用相同的密码和相同的 IP 输入数据库。这可能需要使用 php 服务器上的 mysql 客户端从命令行访问数据库,以确保您的凭据和权限与 php 脚本相同。

CLIDISPLAY 常量仅用于从 CLI 而不是在网页上执行 php(使烦人的条目消失,但在 html 中非常有用)。

【讨论】:

以上是关于mysqli_query 返回 0 行(奇怪的行为)的主要内容,如果未能解决你的问题,请参考以下文章

C ++中的三元运算符奇怪的行为

RegQueryValueEx 的奇怪行为与另一个寄存器的返回值有关

SSIS 查找行为很奇怪

奇怪的预言机工作行为

使用 SWIG 在 Python 中 C++ 类的奇怪行为

Linq 的奇怪行为