Что является причиной ошибки 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, и все они выдают одинаковую ошибку, используя пакеты по умолчанию.
Редактировать:
Чтобы ответить на комментарий Райана Винсента, я - полный нуб, но я полагаю, что то, что я имею ниже, примерно эквивалентно приведенному выше примеру. Пожалуйста, поправьте меня, если я ошибаюсь. Однако он не выдает ошибок, поэтому может показаться, что это ошибка только для 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();
4 ответа
Как ни странно, пакеты 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
,
Это не обязательно ответ на этот вопрос, но это может помочь кому-то в будущем.
Я столкнулся с точно такой же ошибкой, и потребовались часы, чтобы выяснить, в чем дело. Оказалось, что это была исключительно незначительная проблема синтаксиса. Если вы на самом деле не используете буферизацию, но у вас все еще есть эта ошибка, как я, это может быть вашей проблемой - так что проверьте ваш код.
Я выполнял свои обычные запросы к базе данных, когда натолкнулся на эту ошибку - не нарочно используя какие-либо методы буферизации - поэтому я сильно сомневался, что это как-то связано с буферизацией. Я прочитал каждый ТАК вопрос об этом и посмотрел глубже к нему.
Это была моя проблема с синтаксисом STUPID:
$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
установить в ЛОЖЬ.
И в таком случае обязательно убедиться, что больше нет строк, ожидающих получения. Для этого нужно бежать fetch()
один дополнительный раз, так как кажется, что fetch()
возвращение false как-то "освобождает" небуферизованный набор результатов. Без такого дополнительного вызова небуферизованный набор результатов остается заблокированным и вызывает ошибку "Команды не синхронизированы"
Просто для того, чтобы завершить список возможных ошибок, вызывающих эту проблему... потому что я терял голову на этом, я хочу поделиться своим решением / находкой с вами.
В моем случае я попытался отправить несколько операторов в базу данных с помощью PDO::exec
например
self::$objDatabase->exec( "SELECT id from testtable; UPDATE testtable SET name = 'example';" );
Разрешается и сохраняется только 1 оператор SQL в 1 PDO::exec.