PDO::query() наталкивается на "Невозможно выполнить запросы, когда другие небуферизованные запросы активны".

Возможно, у некоторых других есть такая же проблема, как у меня. Я перебил ошибку:

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.

на PDO. Как упоминалось во многих потоках, ошибка может быть как минимум одной из следующих проблем:

  1. Курсор запроса не был закрыт с closeCursor() как упомянуто здесь; Причины ошибки MySQL 2014. Невозможно выполнить запросы, когда другие небуферизованные запросы активны.
  2. Существует более двух запросов с одним оператором, как упомянуто здесь: PDO не может выполнять запросы, когда другие небуферизованные запросы активны
  3. Ошибка в mysql-драйвере, как упомянуто здесь: Что вызывает ошибку PDO Не удается выполнить запросы, когда другие небуферизованные запросы активны?

В моем случае все вышеперечисленное не помогло, и потребовалось некоторое время, чтобы я решил проблему. это был мой код (псевдокод):

$stmt->startTransaction();
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
$stmt->prepare('SELECT * FROM database');
$stmt->execute();
$aData = $stmt->fetchAll();
$stmt->closeCursor();

$stmt->query("USE sometable;");

После того как я изменил его на:

$stmt->startTransaction();
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
$stmt->prepare('SELECT * FROM database');
$stmt->execute();
$aData = $stmt->fetchAll();
$stmt->closeCursor();

$stmt->exec("USE sometable;");

Это сработало для моего. В чем разница между запросом и exec?

PDO::exec() - "Execute an SQL statement and return the number of affected rows"
PDO::query() - "Executes an SQL statement, returning a result set as a PDOStatement object"

Почему в этом случае PDO::query() не работает? Курсор закрывается при вызове.

4 ответа

Хотя вполне возможно, что вы столкнулись с ошибкой драйвера mysql, мы не можем быть в этом уверены, поскольку вы не предоставили нам эту информацию (какую версию PHP вы используете? mysqlnd => проверить с php -i | grep mysqlnd? Как выглядит остальная часть вашего кода?).
Есть много других возможных объяснений вашей проблемы. Я подозреваю, что проблема заключается в том, что вы не можете закрыть все курсоры и / или получить все результаты, потому что $stmt многократно используется:

Цитируется прямо из PDO::query страница справочника:

Если вы не получите все данные в наборе результатов, прежде чем отправлять свой следующий вызов PDO::query() Ваш звонок может не состояться. Вызов PDOStatement::closeCursor() освободить ресурсы базы данных, связанные с PDOStatement возражать, прежде чем сделать следующий вызов PDO::query(),

Ты звонишь closeCursor на $stmt Это правда, но вы не закрыли все созданные вами курсоры:

//<-- what is $stmt here?
$stmt->startTransaction();
//no matter, you've reassigned it a PDOStatement instance
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
//Huh? You're preparing yet another query on an instance of PDOStatement?
$stmt->prepare('SELECT * FROM database');
//you're executing this one, though
$stmt->execute();
//and fetching all data
$aData = $stmt->fetchAll();
//and closing this last statement
$stmt->closeCursor();

Но как насчет первого заявления, которое вы назначили $stmt (вызов хранимой процедуры)? Этот курсор нигде не закрыт

Теперь для основной разницы между PDO::query а также PDO::exec, Опять цитируем руководство:

PDO::exec() не возвращает результаты из оператора SELECT.

В то время как:

PDO::query() выполняет оператор SQL в одном вызове функции, возвращая результирующий набор (если есть), возвращенный оператором, как PDOStatement объект.

Я тоже сталкивался с этой проблемой. Это может быть ошибка. Если мы возьмем следующий код, вы увидите, как он выходит из строя, с сообщением "Общая ошибка: 2014 г. Невозможно выполнить запросы, когда другие небуферизованные запросы активны. Попробуйте использовать PDOStatement::fetchAll().'

$pdo = new \PDO("mysql:host=localhost", "root", "");
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);

$pdo->query("USE test");

Если вы измените $pdo->query("USE test"); в $pdo->exec("USE test"); это будет работать. Если вы измените $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); в $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); это тоже будет работать. Я пока не смог найти правильного решения.

Решаю вопрос по шагам:

После выполнения: $stmt = db::getInstance()->prepare("ПОЗВОНИТЬ на телефоны (:phone)");

Я закрываю: $stmt->startTransaction();

И после этого я снова открываю транзакцию, чтобы использовать запрос ниже: $stmt->prepare('SELECT * FROM database');

Мое решение: одна инструкция для вызова процедуры "CALL phones(:phone)", а другая - для выполнения запроса с "SELECT * FROM database".

Вот и все.

Будьте осторожны. Это также может произойти, если вы пытаетесь получить запрос без SELECT (например, UPDATE/INSERT/ALTER/CREATE).

Другие вопросы по тегам