我有以下代码:
$dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $dbh->prepare("SELECT 1");
$stmt->execute();
$result = $stmt->fetch();
$stmt->execute();
$result = $stmt->fetch();
$stmt = $dbh->prepare("SELECT 1");
$stmt->execute();
$result = $stmt->fetch();
但是,由于某种原因,我在执行第二个预准备语句时出现以下错误:
致命错误:未捕获的异常"PDOException",并显示消息 'SQLSTATE[HY000]:一般错误:2014 无法执行查询,而 其他未缓冲的查询处于活动状态。考虑使用 PDOStatement::fetchAll().或者,如果您的代码只是永远 要针对 MySQL 运行,您可以通过设置 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY属性。
我知道这个错误意味着什么以及如何修复它(要么做unset($stmt);
要么$stmt->closeCursor();
),所以我不是在寻找如何让它工作的解决方案。据我了解,这通常是由于执行fetch
而不是fetchAll
并且没有获取所有结果引起的。但是,在这种情况下,只有一个结果,并且正在获取该结果。此外,如果我只执行第一个预准备语句一次,则不会发生错误。仅当第一个语句执行两次时,才会发生这种情况。它也只发生在PDO::ATTR_EMULATE_PREPARES
false
时。
所以我的问题是,在这种情况下导致上述错误发生的原因是什么?它似乎与我执行过的任何其他查询没有任何不同。
我已经在两台 Ubuntu 13.10 服务器 Debian 和 CentOS 上对此进行了测试,并且都使用默认软件包产生相同的错误。
编辑:
为了回答 Ryan Vincent 的评论,我是一个完整的 mysqli 菜鸟,但我相信我下面的内容大致相当于上面的例子。如果我错了,请纠正我。但是,它不会产生任何错误,因此它似乎是仅 PDO 的错误:
$mysqli = new mysqli($host, $user, $pass, $dbname);
if ($mysqli->connect_errno) {
die("Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error);
}
if (!($stmt = $mysqli->prepare("SELECT 1"))) {
die("Prepare 1 failed: (" . $mysqli->errno . ") " . $mysqli->error);
}
if (!$stmt->execute()) {
die("Execute 1 failed: (" . $stmt->errno . ") " . $stmt->error);
}
$stmt->store_result();
$stmt->bind_result($col1);
$stmt->fetch();
if (!$stmt->execute()) {
die("Execute 2 failed: (" . $stmt->errno . ") " . $stmt->error);
}
$stmt->store_result();
$stmt->bind_result($col1);
$stmt->fetch();
if (!($stmt = $mysqli->prepare("SELECT 1"))) {
// The following line is what fails in PDO
die("Prepare 2 failed: (" . $mysqli->errno . ") " . $mysqli->error);
}
if (!$stmt->execute()) {
die("Execute 3 failed: (" . $stmt->errno . ") " . $stmt->error);
}
$stmt->store_result();
$stmt->bind_result($col1);
$stmt->fetch();
奇怪的是,Ubuntu 提供的 PHP 包不是使用 Mysql 原生驱动程序编译的,而是使用旧的 libmysqlclient 编译的(在 Ubuntu 13.10 上使用默认软件包进行了测试):
<?php
echo $dbh->getAttribute(PDO::ATTR_CLIENT_VERSION); // prints "5.5.35", i.e MySQL version
// prints "mysqlnd (...)" when using mysqlnd
您的测试用例("Edit 4",带有setAttribute(MYSQL_ATTR_USE_BUFFERED_QUERY, true)
)在 PHP 5.5.3 中按预期工作,使用 mysqlnd 手动编译:
./configure --with-pdo-mysql=mysqlnd # default driver since PHP v5.4
。但失败并显示:
bash> ./configure --with-pdo-mysql=/usr/bin/mysql_config
奇怪的是,只有当第一个语句执行两次时,它才会失败;这一定是libmysqlclient驱动程序中的一个错误。
当MYSQL_ATTR_USE_BUFFERED_QUERY
false
时,两个驱动程序都按预期失败。您的常识已经说明了为什么这是预期行为,无论结果集中的行数如何。
Mike发现当前的解决方法是安装php5-mysqlnd
软件包,而不是Canonical推荐的php5-mysql
。
这不一定是这个问题的答案,但这可能会在未来帮助某人。
我遇到了完全相同的错误,花了几个小时才发现出了什么问题。事实证明,这一直只是一个极其小的语法问题。如果您实际上没有使用任何缓冲,但仍然像我一样出现此错误,这可能是您的问题 - 因此请检查您的代码。
当我遇到此错误时,我正在执行正常的数据库查询 - 不是故意使用任何缓冲技术 - 所以我非常怀疑它与缓冲有关。我阅读了有关它的每一个SO问题,并深入研究了它。
这是我愚蠢的语法问题:
$SQL = "UPDATE articles SET
topicID = :topic; <-------- semicolon - woops!
heading = :heading,
subheading = :subheading,
keywords = :keywords,
rawContent = :rawContent,
content = :content,
...
...
这导致我收到此缓冲错误。我修复了代码,它消失了。最烦人的是,PDO错误指向另一个查询,下一个查询,但该查询在代码中其他地方的函数中,并且通过我有一段时间偏离了轨道!
看来你PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
设置为 FALSE。
在这种情况下,必须确保没有更多的行待检索。要这样做,需要额外运行一次fetch()
,因为似乎fetch()
返回 false 会以某种方式"释放"非缓冲结果集。如果没有这种额外的调用,非缓冲结果集将保持锁定状态,并导致"命令不同步"错误
只是为了完成导致此问题的可能错误列表......因为我在这方面失去了头发,我想与您分享我的解决方案/发现。
就我而言,我尝试使用 PDO::exec 向数据库发送了几个语句
例如
self::$objDatabase->exec( "SELECT id from testtable; UPDATE testtable SET name = 'example';" );
只允许在 1 个 PDO::exec 中保存 1 个 SQL 语句。