Подтвердить что ты не робот

Что вызывает ошибку 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();
4b9b3361

Ответ 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.