【发布时间】:2014-05-13 07:01:32
【问题描述】:
我有以下代码:
$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();
但是,由于某种原因,在执行 second 准备好的语句时出现以下错误:
致命错误:带有消息的未捕获异常“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-only 错误:
$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();
【问题讨论】:
-
SHOW TRIGGERS返回一个空的结果集,所以我猜不是。上面的测试用例是一个新创建的数据库。 -
在这种情况下,无论是真还是假,我都会收到错误消息,但我知道应用程序的其余部分设置为真,因为当我将其设置为假时,我开始在各处收到错误.这是唯一在缓冲为真时出现此错误的地方。
-
“但是在这种情况下,只有一个结果并且正在被获取” – 这并不重要,因为此时没有人知道 这是唯一的结果记录。 (也许你除外,因为你知道你在查询中输入了
LIMIT 1……但其他相关方并不关心。) - “这对我来说根本没有意义,因为错误基本上意味着存在是更多的行” – 不,这并不意味着;这意味着目前还不清楚如果还有更多的结果记录。调用nextRowset“修复”了这个,因为现在,在返回false之后,它是清晰的。 -
您是否尝试过使用“mysqli”类的相同示例代码?我的理解是他们(PDO 和 mysqli)在 PHP 中使用不同的驱动程序。根据文档,您正在做“正确的事情”。
-
我在猜测,但有趣的是,您使用 PDO 执行了两个相同的“准备”语句,并且它经常“砰”地一声。我怀疑您遇到的驱动程序中存在“优化”逻辑。因此,在您的 PDO 示例中,要么在第二个准备之前取消设置第一个 '$stmt' 变量,要么使用一个新的 $stmtAnother' 变量来说服驱动程序重建查询。这都是猜测。这是我的意见,它是免费并且值得完全您为它付出的。
标签: php mysql pdo prepared-statement unbuffered-queries