MySQL错误2014的原因其他未缓冲的查询处于活动状态时无法执行查询

我的服务器运行CentOS 6.4,并使用yum和CentOS的存储库安装MySQL 5.1.69,以及使用yum和ius的存储库安装的PHP 5.4.16。Edit3升级到MySQL服务器版本:5.5.31由IUS社区项目分发,并且错误仍然存在。然后将库更改为mysqlnd,似乎消除了该错误。仍然要反复进行此操作,以了解为什么有时仅出现此错误。


使用PDO并使用创建PDO对象时PDO::ATTR_EMULATE_PREPARES=>false,有时会出现以下错误:


Table Name - zipcodes

Error in query:

SELECT id FROM cities WHERE name=? AND states_id=?

SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.

File Name: /var/www/initial_install/build_database.php

Line: 547

Time of Error: Tuesday July 2, 2013, 5:52:48 PDT

547行是以下内容的最后一行:


$stmt_check_county->execute(array($data[5],$data[4]));

if(!$county_id=$stmt_check_county->fetchColumn())

{

    $stmt_counties->execute(array($data[5]));

    $county_id=db::db()->lastInsertId();

}

//$stmt_check_county->closeCursor(); //This will fix the error

$stmt_check_city->execute(array($data[3],$data[4]));

几年前,我遇到了类似的问题,但是从PHP 5.1升级到PHP 5.3(并且MySQL可能也进行了更新),该问题神奇地消失了,现在我使用PHP 5.5。


为什么它只在时出现PDO::ATTR_EMULATE_PREPARES=>false,并且只有PHP的交替版本?


我还发现这closeCursor()也可以修复错误。是否应该始终SELECT在fetchAll()不使用每个查询之后执行此操作?请注意,即使查询SELECT COUNT(col2)仅返回一个值,该错误仍然会发生。


守候你守候我
浏览 1647回答 3
3回答

HUWWW

MySQL客户端协议不允许进行多个查询。也就是说,您已经执行了查询,并且已经获取了一些结果,但不是全部—然后尝试执行第二个查询。如果第一个查询仍有要返回的行,则第二个查询将收到错误。客户端库通过在首次获取时隐式获取第一个查询的所有行来解决此问题,然后后续获取仅对内部缓存的结果进行迭代。这给他们提供了关闭游标的机会(就MySQL服务器而言)。这就是“缓冲查询”。这与使用fetchAll()相同,这两种情况都必须在PHP客户端中分配足够的内存以容纳完整的结果集。不同之处在于,缓冲的查询将结果保存在MySQL客户端库中,因此,只有在依次提取(fetch())每行之后,PHP才能访问这些行。而fetchAll()立即为所有结果填充一个PHP数组,从而允许您访问任何随机行。不使用fetchAll()的主要原因是结果可能太大而无法容纳在您的PHP memory_limit中。但是看来您的查询结果仍然只有一行,所以这应该不是问题。您可以先关闭closeCursor()以“放弃”结果,然后再获取最后一行。MySQL服务器收到通知,可以在服务器端放弃该结果,然后可以执行另一个查询。在完成获取给定结果集之前,您不应该关闭closeCursor()。另外:我注意到您在循环内一遍又一遍地执行$ stmt2,但是每次都会返回相同的结果。根据将循环不变代码移出循环的原理,您应该在开始循环之前执行一次,并将结果保存在PHP变量中。因此,无论使用缓冲查询还是fetchAll(),都无需嵌套查询。因此,我建议您以这种方式编写代码:$sql ='SELECT temp_id FROM temp1';$stmt2 = db::db()->prepare($sql);$stmt2->execute();$rs2 = $stmt2->fetchAll(PDO::FETCH_ASSOC);$stmt2->closeCursor();$sql='SELECT COUNT(*) AS valid FROM cities_has_zipcodes       WHERE cities_id=:cities_id AND zipcodes_id=:zipcodes_id';$stmt1 = db::db()->prepare($sql);foreach($data AS $row){    try    {        $stmt1->execute($row);        $rs1 = $stmt1->fetchAll(PDO::FETCH_ASSOC);        $stmt1->closeCursor();        syslog(LOG_INFO,'$rs1: '.print_r($rs1[0],1).' '.rand());        syslog(LOG_INFO,'$rs2: '.print_r($rs2[0],1).' '.rand());    }    catch(PDOException $e){echo(sql_error($e));}            }注意我还使用了命名参数而不是位置参数,这使得将$ row作为参数值数组进行传递更加简单。如果数组的键与参数名称匹配,则只需传递数组即可。在旧版本的PHP中,您必须:在数组键中包含前缀,但是您不再需要该前缀。无论如何,您应该使用mysqlnd。它具有更多功能,具有更高的内存效率,并且其许可证与PHP兼容。

缥缈止盈

我希望有一个比以下更好的答案。尽管其中一些解决方案可以“解决”问题,但它们并未回答有关导致此错误的原因的原始问题。设置PDO::ATTR_EMULATE_PREPARES=>true(我不希望这样做)设置PDO::MYSQL_ATTR_USE_BUFFERED_QUERY(对我不起作用)使用PDOStatement::fetchAll()(并非总是可取的)$stmt->closeCursor()每次使用之后$stmt->fetch()(大多数情况下可以使用,但是我仍然有几种情况没有使用)将PHP MySQL库从php-mysql更改为php-mysqlnd(如果没有更好的答案,我可能会怎么做)

慕标5832272

我几乎有同样的问题。连接到数据库后,我的第一个查询返回空结果并删除此错误。启用缓冲区没有帮助。我的连接代码是:try {     $DBH = new PDO("mysql:host=$hostname;dbname=$db_name", $username, $password,     array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET utf8; SET NAMES utf8",    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_NUM));} catch(PDOException $e) { echo $e->getMessage(); }我的解决方案是删除初始命令:PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET utf8; SET NAMES utf8"这是正确的代码:try {     $DBH = new PDO("mysql:host=$hostname;dbname=$db_name", $username, $password,     array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_NUM));} catch(PDOException $e) { echo $e->getMessage(); }并且MYSQL_ATTR_USE_BUFFERED_QUERY不是强制为true。设置为默认值。
打开App,查看更多内容
随时随地看视频慕课网APP