Mysqli дает ошибку "Commands out of sync" - почему?
Я пытаюсь запустить следующее.
<?php
$db = mysqli_connect("localhost","user","pw") or die("Database error");
mysqli_select_db($db, "database");
$agtid = $_POST['level'];
$sql = sprintf("call agent_hier(%d)", $agtid);
$result = mysqli_query($db, $sql) or exit(mysqli_error($db));
if ($result) {
echo "<table border='1'>
<tr><th>id</th>
<th>name</th>
<th>parent_id</th>
<th>parent_name</th>
<th>level</th>
<th>email</th></tr>";
while ($row = mysqli_fetch_assoc($result))
{
$aid = $row["id"];
$sql2 = "SELECT * FROM members WHERE MEMNO = '$aid'";
$result2 = mysqli_query($db,$sql2) or exit(mysqli_error($db));
while ($newArray = mysqli_fetch_array($result2)) {
$fname = $newArray['FNAME'];
$lname = $newArray['LNAME'];
$mi = $newArray['MI'];
$address = $newArray['ADDRESS'];
$city = $newArray['CITY'];
$state = $newArray['STATE'];
$zip = $newArray['ZIP'];
$kdate = $newArray['KDATE'];
$date = abs(strtotime(date('m/d/Y')) - strtotime(date($kdate))) / (60 * 60 * 24);
}
echo sprintf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",
$row["id"],$row["name"],
$row["parent_id"],$row["parent_name"],
$row["level"],$row["email"]);
}
echo "</table>";
}
mysqli_free_result($result);
mysqli_close($db);
?>
Если я удаляю строки из:
$aid = $row["agent_id"];
в....
$date = abs(strtotime(date('m/d/Y')) - strtotime(date($kdate))) / (60 * 60 * 24);
}
все будет хорошо работать. Если нет, я получаю следующую ошибку:
Команды не синхронизированы; вы не можете запустить эту команду сейчас
При исследовании я думаю, что это может быть связано с одновременным запуском нескольких запросов MySQLi, в которых используется mysqli_multi_query
, но для всех образцов и общих данных в руководство, похоже, не применимо.
Любые идеи?
Ответы
Ответ 1
Клиент MySQL не позволяет вам выполнять новый запрос, в котором все еще есть строки, которые должны быть получены из текущего запроса. См. Команды не синхронизированы в документе MySQL о распространенных ошибках.
Вы можете использовать mysqli_store_result()
для предварительной выборки всех строк из внешнего запроса. Это буферизует их в клиенте MySQL, поэтому с точки зрения сервера ваше приложение получает полный набор результатов. Затем вы можете выполнять больше запросов даже в цикле извлечения строк из внешнего набора результатов с буфером.
Или вы mysqli_result::fetch_all()
, который возвращает полный набор результатов как массив PHP, а затем вы можете перебрать этот массив.
Вызов хранимых процедур - это особый случай, поскольку хранимая процедура имеет потенциал для возврата нескольких наборов результатов, каждый из которых может иметь свой собственный набор строк. Вот почему ответ от @a1ex07 упоминает использование mysqli_multi_query()
и цикл до тех пор, пока mysqli_next_result()
не будет иметь больше наборов результатов. Это необходимо для удовлетворения протокола MySQL, даже если в вашем случае ваша хранимая процедура имеет единственный результирующий набор.
PS: Кстати, я вижу, что вы выполняете вложенные запросы, потому что у вас есть данные, представляющие иерархию. Возможно, вы захотите рассмотреть возможность хранения данных по-разному, чтобы упростить запрос. Я сделал презентацию об этом под названием Модели для иерархических данных с SQL и PHP. Я также освещаю эту тему в главе моей книги SQL Antipatterns: устранение ошибок программирования баз данных.
Вот как реализовать mysqli_next_result()
в CodeIgnitor 3.0.3:
В строке 262 из system/database/drivers/mysqli/mysqli_driver.php
измените
protected function _execute($sql)
{
return $this->conn_id->query($this->_prep_query($sql));
}
к этому
protected function _execute($sql)
{
$results = $this->conn_id->query($this->_prep_query($sql));
@mysqli_next_result($this->conn_id); // Fix 'command out of sync' error
return $results;
}
Это проблема с 2.x. Я просто обновился до 3.x и должен был скопировать этот хак в новую версию.
Ответ 2
Просто,
Вызов mysqli_next_result ($ db), после вызова mysqli_free_result.
mysqli_free_result ($ результат);
mysqli_next_result ($ дБ)
mysqli_close ($ дБ);
Ответ 3
просто вызовите эту функцию:
$this->free_result();
function free_result() {
while (mysqli_more_results($this->conn) && mysqli_next_result($this->conn)) {
$dummyResult = mysqli_use_result($this->conn);
if ($dummyResult instanceof mysqli_result) {
mysqli_free_result($this->conn);
}
}
}
Ответ 4
Вам нужно закрыть предыдущее соединение с помощью хранимой процедуры.
Вместо закрытия соединения каждый раз вы можете просто использовать:
mysqli_next_result($conn);
Ответ 5
Если вы также выполняете несколько вызовов хранимых процедур и сталкиваетесь с вышеупомянутой ошибкой, у меня есть решение для вас, Mr. Wayne.
ИМХО, Где-то по линии, CALL
до Stored Procedure
фактически испортило соединение. Итак, все, что вам нужно сделать, это reset дескриптор подключения базы данных.
У вас может даже быть функция, сидящая в вашем файле конфигурации, которая делает именно это для вас, и все, что вы делаете, - это вызов этой функции один раз, прежде чем сделать query
или CALL
в Stored Procedure
Моя реализация (просто игнорируйте $app
, так как я работаю над фреймворком silex
там, YMMV)
function flushhandle() {
global $app;
global $db_host;
global $db_user;
global $db_pass;
global $db_name;
$app['mysqlio']->close();
$app['mysqlio'] = new mysqli($db_host, $db_user, $db_pass, $db_name);
return $app['mysqlio'];
}