Что вызывает ошибку PDO Не удается выполнить запросы, в то время как другие небуферизованные запросы активны?
У меня есть следующий код:
$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, и все они вызывают ту же ошибку, используя пакеты по умолчанию.
Edit:
Чтобы ответить на комментарий Райана Винсента, я полный mysqli noob, но я считаю, что то, что у меня ниже, примерно эквивалентно приведенному выше примеру. Пожалуйста, поправьте меня, если я ошибаюсь. Однако он не вызывает ошибок, поэтому он выглядит как ошибка 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();
Ответы
Ответ 1
Как ни странно, пакеты PHP, предоставляемые Ubuntu, не скомпилированы с помощью родного драйвера 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
Ваш тестовый пример ( "Редактировать 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
. Ваше общее чувство уже продемонстрировало, почему это ожидаемое поведение, независимо от количества строк в наборе результатов.
Майк узнал, что в текущем обходном пути устанавливается пакет php5-mysqlnd
вместо рекомендуемого Canonical php5-mysql
.
Ответ 2
Кажется, у вас PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
установлено значение FALSE.
И в таком случае обязательно убедиться, что для поиска больше нет ожидающих строк. Для этого нужно запустить fetch()
одно дополнительное время, так как кажется, что fetch()
return false - это "освобождение" небуферизованных результатов как-то. Без такого дополнительного запроса небуферизованные результирующие данные остаются заблокированными и вызывают ошибку "Commands out of sync"
Ответ 3
Это не обязательно ответ на этот вопрос, но это может помочь кому-то в будущем.
Я столкнулся с той же ошибкой, и мне потребовалось несколько часов, чтобы узнать, что случилось. Оказалось, что это была всего лишь незначительная проблема синтаксиса. Если вы на самом деле не используете какую-либо буферизацию, но все еще имеете эту ошибку, как и я, это может быть вашей проблемой, поэтому проверьте свой код.
Я делал свои обычные запросы к базе данных, когда сталкивался с этой ошибкой - не намеренно использую какие-либо методы буферизации, поэтому я очень сомневался, что это связано с буферизацией. Я прочитал каждый вопрос о нем и посмотрел на него глубже.
Это была моя проблема с синтаксисом STUPID:
$SQL = "UPDATE articles SET
topicID = :topic; <-------- semicolon - woops!
heading = :heading,
subheading = :subheading,
keywords = :keywords,
rawContent = :rawContent,
content = :content,
...
...
В результате я получил эту ошибку буферизации. Я исправил код, и он ушел. То, что было самым раздражающим, было то, что ошибка PDO указывала на другой запрос, следующий запрос, но этот запрос был в функции в другом месте кода, и что через меня хорошо прошел курс на некоторое время!
Ответ 4
Просто чтобы заполнить список возможных ошибок, вызвавших эту проблему... потому что я терял свои волосы, я хочу поделиться с вами своим решением/поиском.
В моем случае я попытался отправить несколько операторов в базу данных с помощью PDO:: exec
например.
self::$objDatabase->exec( "SELECT id from testtable; UPDATE testtable SET name = 'example';" );
Разрешено и сохраняется только 1 SQL-выражение в 1 PDO:: exec.