PDO Небуферизованные запросы
Я пытаюсь вникнуть в детали PDO. Итак, я закодировал это:
$cn = getConnection();
// get table sequence
$comando = "call p_generate_seq('bitacora')";
$id = getValue($cn, $comando);
//$comando = 'INSERT INTO dsa_bitacora (id, estado, fch_creacion) VALUES (?, ?, ?)';
$comando = 'INSERT INTO dsa_bitacora (id, estado, fch_creacion) VALUES (:id, :estado, :fch_creacion)';
$parametros = array (
':id'=> (int)$id,
':estado'=>1,
':fch_creacion'=>date('Y-m-d H:i:s')
);
execWithParameters($cn, $comando, $parametros);
моя функция getValue работает нормально, и я получаю следующую последовательность для таблицы. Но когда я вхожу в execWithParameters, я получаю это исключение:
PDOException: SQLSTATE [HY000]: общая ошибка: 2014 Невозможно выполнить запросы, когда другие небуферизованные запросы активны. Рассмотрите возможность использования PDOStatement::fetchAll(). В качестве альтернативы, если ваш код работает только с mysql, вы можете включить буферизацию запросов, установив атрибут PDO::MYSQL_ATTR_USE_BUFFERED_QUERY. в D:\Servidor\xampp_1_7_1\htdocs\bitacora\func_db.php в строке 77
Я пытался изменить атрибуты подключения, но это не работает.
Это мои основные функции БД:
function getConnection() {
try {
$cn = new PDO("mysql:host=$host;dbname=$bd", $usuario, $clave, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
));
$cn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
return $cn;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}
function getValue($cn, $comando) {
$resul = $cn->query($comando);
if (!$resul) return null;
while($res = $resul->fetch()) {
$retorno = $res[0][0];
break;
}
return $retorno;
}
function execWithParameters($cn, $comando, $parametros) {
$q = $cn->prepare($comando);
$q->execute($parametros);
if ($q->errorInfo() != null) {
$e = $q->errorInfo();
echo $e[0].':'.$e[1].':'.$e[2];
}
}
Кто-нибудь, кто может пролить свет на это? Оплаченный Пожалуйста, не предлагайте делать авто-числовой идентификатор, потому что я портирую из другой системы.
6 ответов
Проблема в том, что mysql допускает только один выдающийся курсор в данный момент времени. Используя метод fetch() и не используя все ожидающие данные, вы оставляете курсор открытым.
Рекомендуемый подход - использовать все данные, используя метод fetchAll(). Альтернативой является использование метода closeCursor().
Если вы измените эту функцию, я думаю, что вы будете счастливее:
<?php
function getValue($cn, $comando) {
$resul = $cn->query($comando);
if (!$resul) return null;
foreach ($resul->fetchAll() as $res) {
$retorno = $res[0];
break;
}
return $retorno;
}
?>
Я не думаю, что PDOStatement::closeCursor() будет работать, если вы не выполняете запрос, который возвращает данные (например, UPDATE, INSERT и т. Д.).
Лучшее решение - просто удалить () ваш объект PDOStatement после вызова PDOStatement::execute():
$stmt = $pdo->prepare('UPDATE users SET active = 1');
$stmt->execute();
unset($stmt);
Кажется, проблема в том, что я не слишком знаком с PDO, что после того, как ваш вызов getValue возвращается, запрос все еще привязан к соединению (вы когда-либо запрашиваете только первое значение, но соединение возвращает несколько, или рассчитывает на это).
Возможно, getValue можно исправить, добавив
$resul->closeCursor();
до возвращения.
В противном случае, если запросы к getValue всегда будут возвращать одно (или несколько) значение, кажется, что использование fetchAll будет предпочтительным.
Я просто потратил 15 минут на поиски в интернете и просмотрел по крайней мере 5 различных вопросов Stackru, некоторые из которых утверждали, что моя ошибка, по-видимому, возникла из-за неправильной версии PHP, неправильной версии библиотеки MySQL или любых других волшебных черных ящиков...
Я изменил весь свой код на использование "fetchAll" и даже вызывал closeCursor() и unset() для объекта запроса после каждого запроса. Я был в отчаянии! Я также попробовал флаг MYSQL_ATTR_USE_BUFFERED_QUERY, но он не работал.
Наконец, я выбросил все в окно, посмотрел на ошибку PHP и отследил строку кода, где это произошло.
SELECT AVG((original_bytes-new_bytes)/original_bytes) as saving
FROM (SELECT original_bytes, new_bytes FROM jobs ORDER BY id DESC LIMIT 100) AS t1
В любом случае, проблема возникла из-за того, что мои original_bytes и new_bytes были неподписанными bigints, и это означало, что если бы у меня когда-нибудь была работа, где new_bytes на самом деле БОЛЬШЕ, чем original_bytes, то у меня была бы неприятная ошибка MySQL "вне диапазона". И это произошло случайно после небольшого запуска моей службы минификации.
Почему, черт возьми, я получил эту странную ошибку MySQL вместо того, чтобы просто дать мне простую ошибку, мне не под силу! Это на самом деле обнаружилось в SQLBuddy (облегченный PHPMyAdmin), когда я запустил необработанный запрос. У меня были исключения PDO, поэтому он должен был дать мне ошибку MySQL.
Неважно, суть заключается в следующем:
Если вы когда-нибудь получите эту ошибку, убедитесь, что ваш сырой MySQL действительно корректен и все еще работает!!!
Если вы используете XAMPP 1.7.1, вам просто нужно перейти на 1.7.2.
У моего друга была такая же проблема со сборкой xampp 1.7.1. После замены xampp/php/* сборкой php.net 5.2.9-2 и копирования всех необходимых файлов в xampp/apache/bin все заработало нормально.