我知道这个问题已经被问过很多次了,但我已经阅读了很多问题的答案,但仍然不明白为什么我会收到这个错误:
Fatal error: Uncaught exception 'PDOException' with message '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.'
第一件奇怪的事情是,我在本地主机 (wampserver) 上没有收到错误,但在我的网络服务器上却收到了错误。我本地主机上的 php 版本是 5.3.10,在我的网络服务器上是 5.3.13。
我读到此错误的来源是当数据从先前的查询留在缓冲区中时进行查询。对我来说情况并非如此——我已经回显了所有数据,而且我知道查询中返回的每一行都被提取了。
话虽如此,我发现将我的一个查询更改为 fetchAll
而不是 fetch
可以解决问题,但它根本就没有,因为我 知道 正在读取所有返回的行。当我使用 fetchAll
进行查询时(它是在一个循环中进行的),我在每个循环中打印出数组,并且对于循环中的每个查询,数组中只有一个项目。
还有一条信息。抛出 PDO 错误的不是我更改为 fetchAll
的查询(这使得错误消失),我的 php 文件中稍后有另一个查询抛出错误。我的文件基本上是这样的:
... code ...
query 1
... code ...
loop
query 2
end loop
... code ...
query 3
如果我注释掉查询 3,则没有错误。如果我注释掉,或者改成fetchAll
,查询2,就没有错误了。查询 1 没有任何影响。
我还想补充一点,我已经尝试将 LIMIT 1
添加到页面上的所有查询(同时),但错误仍然存在那里。我认为这证明缓冲区中没有未读数据,对吧?
我真的很困惑,所以我很感激你的建议。在有人问之前,我无法发布完整的代码,但这是我的代码的简化版本:
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
makeQuery($stmt, array(':par' => $var));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
for loop
makeQuery($stmt, array(':par' => $var));
$row2 = $stmt->fetch(PDO::FETCH_ASSOC);
... [use row2] ...
end for loop
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
makeQuery($stmt, array(':par' => $var));
$row3 = $stmt->fetch(PDO::FETCH_ASSOC);
这里是makeQuery()
。
/**************************************************************************************************************
* Function: makeQuery *
* Desc: Makes a PDO query. *
* Pre conditions: The statement/query and an array of named parameters (may be empty) must be passed. *
* Post conditions: The PDO query is executed. Exceptions are caught, displayed, and page execution stopped. *
**************************************************************************************************************/
function makeQuery($stmt, $array, $errMsg = '')
{
try
{
$stmt->execute($array);
}
catch (PDOException $e)
{
print $errMsg != ''?$errMsg:"Error!: " . $e->getMessage() . "<br/>";
die();
}
}
感谢您的帮助!
编辑:我还尝试在查询 2 之后执行以下操作(因为这似乎是问题的根源:
$row2 = $stmt->fetch(PDO::FETCH_ASSOC); var_dump($row2);
输出是:
bool(false)
我是否遇到了 PDO 错误?
最佳答案
您需要获取直到行获取尝试失败。我知道您可能在结果集中只有一行,并且认为一次提取就足够了,但事实并非如此(当您使用无缓冲查询时)。 PDO 在到达末尾之前不知道有多少行,它会尝试获取下一行,但失败了。
您可能还有其他语句没有完全“获取直到获取失败”。是的,我看到您一直在提取,直到一个 语句的提取失败,但这并不意味着您对所有语句都这样做了。
为了澄清—— 当您通过 execute() 执行查询时,您会创建一个结果集,该结果集必须从数据库中提取到 php 中。 PDO 一次只能处理这些“正在获取的结果集”中的 1 个(每个连接)。您需要完全获取结果集,一直到它的末尾,然后才能开始从对 execute() 的不同调用获取不同的结果集。
当您“调用 fetch() 直到 fetch() 失败”时,当最终调用 fetch() 由于没有更多结果而失败时,PDO 会在内部记录您到达结果末尾的事实。然后 PDO 对结果被完全获取感到满意,并且它可以清理 php 和为该结果集建立的 db 之间的任何内部资源,允许您进行/获取其他查询。
还有其他方法可以使 PDO“调用 fetch() 直到 fetch() 失败”。
- 只需使用 fetchAll(),它会简单地获取所有行,因此它会到达结果集的末尾。
- 或者直接调用 closeCursor()
*如果您查看 closeCursor() 的源代码,默认实现实际上只是获取行并丢弃它们,直到到达末尾。它显然是用 c 语言编写的,但或多或少是这样做的:
function closeCursor() {
while ($row = $stmt->fetch()) {}
$this->stmtFullyFetched = true;
}
一些数据库驱动程序可能有一个更高效的实现,不需要它们获取很多没人关心的行,但这是 PDO 的默认方式。无论如何...
通常在使用缓冲查询时不会遇到这些问题。原因是因为对于缓冲查询,在您执行它们之后,PDO 会自动将数据库结果完全提取到 php 内存中,因此它会自动为您执行“调用 fetch() 直到 fetch() 失败”部分。当您稍后自己调用 fetch() 或 fetchAll() 时,它是从 php 内存中获取结果,而不是从数据库中获取结果。所以基本上,在使用缓冲查询时会立即完全获取结果集,因此没有机会同时拥有超过 1 个“正在获取的结果集”(因为 php 是单线程的,所以没有机会进行 2 个查询同时运行)。
鉴于此:
$sql = "select * from test.a limit 1";
$stmt = $dbh->prepare($sql);
$stmt->execute(array());
完全获取结果集的方法(假设您只想要第一行):
$row = $stmt->fetch();
$stmt->closeCursor();
或
list($row) = $stmt->fetchAll(); //tricky
或
$row = $stmt->fetch();
while ($stmt->fetch()) {}
关于php - PDO “Uncaught exception ' PDOException' .. 当其他无缓冲查询处于事件状态时无法执行查询。考虑使用 PDOStatement::fetchAll()。”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11492644/