【问题标题】:Why does mysql_query() return TRUE with a SELECT statement?为什么 mysql_query() 使用 SELECT 语句返回 TRUE?
【发布时间】:2011-09-06 16:20:03
【问题描述】:

根据mysql_query() 的手册以及我所知道的关于我多次使用的这个函数的所有信息,如果查询是SELECT,它可以返回资源或FALSE。但它会不时返回TRUE

这怎么可能?以前从未发生过。这是 PHP 5.3.2 中的错误吗?有人知道吗?

代码是这样的:

if (!$resource = mysql_query($query, $handle)) {
    throw some exception;
}

var_dump($query);
if ($resource === true && strpos($query, 'SELECT') !== false) {
    throw new Exception('mysql_query() returned TRUE for SELECT');
}

它也很难复制。它只是不时发生。我还注意到这很可能发生在服务器突然中断连接的同时,在这种情况下它应该返回FALSE...

【问题讨论】:

  • 您确定这是您正在使用的查询返回 true 吗?因为 true 应该只用于插入更新或删除。我会检查并确保您没有看到前一个语句的变量结转。
  • 您是如何得出它返回 TRUE 的结论的?在你认为发生这种情况的地方显示一个 sn-p。
  • 添加了一个 sn-p。 var_dump() 清楚地显示了我在普通 MySQL 客户端中运行的普通 SELECT 查询,结果正常。
  • 如果您在查询之前明确将$resource 设置为-1,您还能重现它吗?我想知道在服务器中断的情况下,值是实际更改还是未更新。
  • @James,好主意。错误是:Lost connection to MySQL server during query.。如果发生这种情况,手册指出(并且总是如此)mysql_query() 将返回FALSE,而不是TRUE...但是它确实证实了这种奇怪行为的怀疑,即如果服务器突然丢弃连接...

标签: php mysql


【解决方案1】:

mysql_query 不返回 FALSE,更不用说 TRUE。它返回一个资源 ID,如果等于零,则将其视为 FALSE。我的例子是为了说明布尔结果

$resource = mysql_query($query, $handle);
if (!$resource) throw some exception;
if (!$resource && strpos($query, 'SELECT')) {
throw new Exception('mysql_query() returned TRUE for SELECT');
}

PHP Booleans

【讨论】:

  • mysql_query 不返回 FALSE,更不用说 TRUE。它返回一个资源 ID,如果等于零,则将其视为 FALSE。我的例子是为了说明布尔结果。
  • 史蒂夫,下一次,请编辑你的答案并增强它。这次我为你做了,并且投了赞成票。
【解决方案2】:

对于SELECT, SHOW, DESCRIBE, EXPLAIN 和其他返回结果集的语句,mysql_query() 成功时返回资源,错误时返回 FALSE。

对于其他类型的 SQL 语句,INSERT, UPDATE, DELETE, DROP 等,mysql_query() 在成功时返回 TRUE,在错误时返回 FALSE

(来自http://php.net/manual/en/function.mysql-query.php

你说 SELECT 会返回 boolean true 吗?不只是不为零的资源:) ?

【讨论】:

  • 这并不能解释为什么它的选择返回 true
  • 是的,它是TRUE。与=== 核对。
  • 选民又一次奇怪了。复制说明 OP 已经知道的确切内容的手册并不能回答问题。
  • 我不能确定,但​​我不记得在回答 Q 时阅读过“仅在选择语句中”部分,而且从那以后它肯定被编辑过。无论如何,对于当前的问题文本,这似乎是一个无用的答案。
【解决方案3】:

如果 webbiedave 没有走上正轨,那么在 php 源代码中只有一个代码路径允许这种情况:

#if MYSQL_VERSION_ID < 32224
#define PHP_MYSQL_VALID_RESULT(mysql)       \
    (mysql_num_fields(mysql)>0)
#else
#define PHP_MYSQL_VALID_RESULT(mysql)       \
    (mysql_field_count(mysql)>0)
#endif

...

if (!mysql_result) {
    if (PHP_MYSQL_VALID_RESULT(mysql->conn)) { /* query should have returned rows */
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to save result set");
        RETURN_FALSE;
    } else {
        RETURN_TRUE; // <<< this case
    }
}

我认为这是一个错误。特别是因为没有真正的方法来验证这一点 - PHP 代码中的 mysql_num_fields 使用的是您没有获得的资源,而不是连接。

虽然 C 版本的 mysql_query 在失去连接时返回零仍然很奇怪 - 如果可以,请尝试以下补丁并重新安装 mysql 扩展:

Index: ext/mysql/php_mysql.c
===================================================================
--- ext/mysql/php_mysql.c       (revision 311719)
+++ ext/mysql/php_mysql.c       (working copy)
@@ -1485,6 +1485,9 @@
                if (PHP_MYSQL_VALID_RESULT(mysql->conn)) { /* query should have returned rows */
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to save result set");
                        RETURN_FALSE;
+               } else if( mysql_errno(mysql->conn) != 0 ) {
+                       php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(mysql->conn));
+                       RETURN_FALSE;
                } else {
                        RETURN_TRUE;
                }

【讨论】:

  • 其实MYSQL_VERSION_ID定义为MYSQLND_VERSION_ID,也就是定义为50007。所以它应该在mysql_field_count() 分支上。
  • 我不确定 mysql_field_count() 函数的作用(会查找),但如果它按照名称所说的那样做,mysql_field_count(mysql) 不会是 0 如果出现问题了吗?
  • @Radu 修改了补丁,里面有错误,mysql_error 应该是 mysql_errno。是的,field_count 应该为零。这是一个不应该发生的经典案例,但我认为我们处于这个错误的领域。
  • @Radu 我明白你的意思。在这种情况下,字段计数始终为零。它仍然会触发警告。但也适用于非选择查询。基本上,查询是有效的,但甚至没有收到字段计数。
  • @Mel, Error with field count &gt; 0: field count = 0
【解决方案4】:

您没有提到数据长度,但您应该检查它是否被超过 max_allowed_packet 调用。

当一个 MySQL 客户端或 mysqld 服务器收到一个大于 max_allowed_pa​​cket 字节,它发出一个 数据包太大错误并关闭 联系。对于一些客户,您可以 也失去了与 MySQL 的连接 服务器在查询错误,如果 通讯包过大。

[...]

客户端和服务器都有 他们自己的 max_allowed_pa​​cket 变量, 所以如果你想处理大数据包, 你必须同时增加这个变量 在客户端和服务器中。

http://dev.mysql.com/doc/refman/5.5/en/packet-too-large.html

不确定 mysql_query 返回值如何受此影响,但值得研究。将其设置为 my.cnf 以查看它是否可以解决问题将是最好的起点。

【讨论】:

  • 确实值得研究。如何找出 PHP 客户端的 max_allowed_packet 是什么?这显然不是服务器上的东西,因为查询很短。
  • 我认为您需要通过mysql_query 发出一条SQL 语句,类似于SET @@max_allowed_packet=NUM 我认为您可以使用缩写符号,例如64MB,但我没有尝试过。
  • @Radu:我不确定如何查看客户端设置。您可以尝试SHOW VARIABLES LIKE 'max_allowed_packet'; mysql 客户端默认为 16MB,因此 PHP 客户端也可能如此。我不确定那个。
  • 这很奇怪。我运行了SET @@max_allowed_packet=64M,然后当它到达使mysql_query() 返回TRUE 的查询时,我收到以下错误:PHP Error (2): mysql_query(): 57 is not a valid MySQL-Link resource。它试图对我用来运行max_allowed_packet 查询的资源进行查询,但它突然变得无效。而且,这种情况时有发生。我的意思是,我仍然得到 TRUE 的东西,但现在我也得到了这个。
  • 顺便说一下,结果集的大小应该在 0.4 MB 左右。而且查询真的很小。我认为不太可能是max_allowed_packet。另外,当我遇到max_allowed_packet 问题时,我得到了一个不同的错误...不记得是哪个错误,但其中包含有关最大数据包大小的信息。
【解决方案5】:

让我们换个角度来看,当mysql_query() 返回FALSE 时,这意味着无论出于何种原因,查询尝试都失败了。这意味着即使在它开始之前,您的查询就出现了问题,因此对数据库没有任何影响,或者查询甚至无法到达它可以看到数据库的地步。

【讨论】:

  • 是的,这是预期的行为。但是,mysql_query() 返回 TRUE,而不是 FALSE
  • @Radu,别忘了,如果 mysql_query 返回 FALSE!$resource = mysql_query($query, $handle) 等同于 TRUE
  • mysql_query() 可以返回 false 并修改数据库。如果您将数据插入 MyISAM 表并在插入几行后遇到错误(重复唯一键等),则 mysql_query() 返回 false(和错误)但行保留在表中。
【解决方案6】:

James 想说的是,如果查询已被正确执行并执行,则函数 mysql_query() 只会返回 true。它与查询产生的结果无关。

如果要实际获取结果,请使用 mysql_fetch_assoc()/mysql_fetch_array()/mysql_results()。

【讨论】:

    【解决方案7】:

    当你说它“返回 TRUE”时,你是如何测试它的?你不会做这种事吧?

    $result = mysql_query($sql);
    if ($result == TRUE) { /* stuff */ }
    

    如果是这样,请记住,返回的所有非零、非空白、非空值都将评估为 TRUE。您可以使用更严格的方法来验证这一点:

    if ($result === TRUE) { /* stuff */ }
    

    这不仅评估等效性,还评估类型。你在做类似 var_export($result); 的事情吗?来检查数据类型并验证您是否真的得到了布尔值 TRUE?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-06
      • 2021-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-10
      • 2014-02-15
      • 1970-01-01
      相关资源
      最近更新 更多