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