ti-enxame.com

Por que o mysqli está fornecendo um erro "Comandos fora de sincronia"?

Estou tentando executar o seguinte.

<?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);

?>

Se eu remover linhas de:

  $aid = $row["agent_id"];

para....

  $date = abs(strtotime(date('m/d/Y')) - strtotime(date($kdate))) / (60 * 60 * 24);
  }

tudo vai funcionar bem. Caso contrário, recebo o seguinte erro:

Comandos fora de sincronia; você não pode executar este comando agora

Ao pesquisar, acho que isso pode ser devido a várias consultas MySQLi executadas ao mesmo tempo, nas quais o uso de mysqli_multi_query mas para todas as amostras e dados gerais em o guia não parece ser aplicável.

Alguma ideia?

22
JM4

O cliente MySQL não permite que você execute uma nova consulta onde ainda existem linhas a serem buscadas a partir de uma consulta em andamento. Veja Comandos fora de sincronia no documento MySQL sobre erros comuns.

Você pode usar mysqli_store_result() para buscar previamente todas as linhas da consulta externa. Isso os armazenará em buffer no cliente MySQL, portanto, do ponto de vista do servidor, seu aplicativo buscou o conjunto completo de resultados. Em seguida, você pode executar mais consultas, mesmo em um loop de busca de linhas do conjunto de resultados externo agora armazenado em buffer.

Ou você mysqli_result::fetch_all() que retorna o conjunto completo de resultados como uma matriz PHP array, e então você pode fazer um loop sobre essa matriz.

Chamar procedimentos armazenados é um caso especial, porque um procedimento armazenado tem o potencial de retornar vários conjuntos de resultados, cada um dos quais pode ter seu próprio conjunto de linhas. É por isso que a resposta de @ a1ex07 menciona usar mysqli_multi_query() e fazer um loop até mysqli_next_result() não ter mais conjuntos de resultados. Isso é necessário para satisfazer o protocolo MySQL, mesmo que no seu caso seu procedimento armazenado tenha um único conjunto de resultados.


PS: A propósito, vejo que você está fazendo consultas aninhadas porque possui dados que representam uma hierarquia. Você pode considerar armazenar os dados de maneira diferente, para poder consultá-los com mais facilidade. Fiz uma apresentação sobre isso intitulada Modelos para Dados Hierárquicos com SQL e PHP . Também abordo este tópico em um capítulo do meu livro Antipatterns SQL: Evitando as Armadilhas da Programação de Banco de Dados .


Aqui está como implementar mysqli_next_result() no CodeIgnitor 3.0.3:

Na linha 262 de system/database/drivers/mysqli/mysqli_driver.php mudança

protected function _execute($sql)
{
    return $this->conn_id->query($this->_prep_query($sql));
}

para isso

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;
}

Esse é um problema desde a versão 2.x. Acabei de atualizar para 3.x e tive que copiar esse hack para a nova versão.

39
Bill Karwin

Simplesmente, você deve chamar mysqli_next_result ($ db), depois que mysqli_free_result for chamado.

mysqli_free_result ($ resultado); mysqli_next_result ($ db) mysqli_close ($ db);

3
Deepan Prabhu Babu

basta chamar esta função:

$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);
            }
        }
    }
3
Rizwan Mirza

Você precisa fechar a conexão anterior em espera pelo Procedimento armazenado. Em vez de fechar a conexão a cada vez, você pode simplesmente usar:

mysqli_next_result($conn);
1
Salman Mohammad