web-dev-qa-db-fra.com

Pourquoi mysqli génère-t-il l'erreur "Commandes désynchronisées"?

J'essaie de lancer ce qui suit.

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

?>

Si je supprime des lignes de:

  $aid = $row["agent_id"];

à....

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

tout fonctionnera bien. Sinon, j'obtiens l'erreur suivante:

Commandes désynchronisées; vous ne pouvez pas exécuter cette commande maintenant

Dans les recherches, je pense que cela pourrait être dû à plusieurs requêtes MySQLi exécutées en même temps, dans lesquelles utiliser mysqli_multi_query mais pour tous les échantillons et données générales dans le guide ne semble pas être applicable.

Des idées?

20
JM4

Le client MySQL ne vous permet pas d’exécuter une nouvelle requête alors qu’il reste encore des lignes à extraire d’une requête en cours. Voir Commandes désynchronisées dans le document MySQL sur les erreurs courantes.

Vous pouvez utiliser mysqli_store_result() pour pré-extraire toutes les lignes de la requête externe. Cela les mettra en mémoire tampon dans le client MySQL. Ainsi, du point de vue du serveur, votre application a récupéré le jeu de résultats complet. Ensuite, vous pouvez exécuter davantage de requêtes, même dans une boucle d'extraction de lignes du jeu de résultats externe désormais mis en mémoire tampon.

Ou vous mysqli_result::fetch_all() qui renvoie le jeu de résultats complet sous la forme d'un tableau PHP et vous pourrez alors effectuer une boucle sur ce tableau.

L'appel de procédures stockées est un cas particulier, car une procédure stockée peut renvoyer plusieurs jeux de résultats, chacun d'entre eux pouvant avoir son propre jeu de lignes. C'est pourquoi la réponse de @ a1ex07 mentionne l'utilisation de mysqli_multi_query() et la mise en boucle jusqu'à ce que mysqli_next_result() ne contienne plus de jeux de résultats. Cela est nécessaire pour satisfaire le protocole MySQL, même si dans votre cas, votre procédure stockée n'a qu'un seul résultat.


PS: Au fait, je vois que vous faites les requêtes imbriquées parce que vous avez des données représentant une hiérarchie. Vous voudrez peut-être envisager de stocker les données différemment afin de pouvoir les interroger plus facilement. J'ai fait une présentation à ce sujet intitulée Modèles pour données hiérarchiques avec SQL et PHP . Je couvre également ce sujet dans un chapitre de mon livre SQL Antipatterns: éviter les pièges de la programmation de base de données .


Voici comment implémenter mysqli_next_result() dans CodeIgnitor 3.0.3:

À la ligne 262 du changement system/database/drivers/mysqli/mysqli_driver.php

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

pour ça

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

Cela pose problème depuis la version 2.x. Je viens de mettre à jour vers 3.x et je devais copier ce hack dans la nouvelle version.

38
Bill Karwin

Simplement, Vous devez appeler mysqli_next_result ($ db) après l’appel de mysqli_free_result.

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

3
Deepan Prabhu Babu

appelez simplement cette fonction: 

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

Vous devez fermer la connexion précédente par la procédure stockée. Au lieu de fermer la connexion à chaque fois, vous pouvez simplement utiliser:

mysqli_next_result($conn);
0
Salman Mohammad