web-dev-qa-db-ja.com

mysqliが「コマンドが同期していません」というエラーを出すのはなぜですか?

以下を実行しようとしています。

<?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を使用しますが、すべてのサンプルと一般的なデータについて ガイド はそうではないようです該当します。

何か案は?

22
JM4

MySQLクライアントでは、進行中のクエリからフェッチされる行がまだある場合、新しいクエリを実行できません。一般的なエラーについては、MySQLドキュメントの Commands out of sync を参照してください。

mysqli_store_result() を使用して、外部クエリからすべての行をプリフェッチできます。これにより、MySQLクライアントでそれらがバッファリングされるため、サーバーの観点からは、アプリは結果セット全体をフェッチします。その後、バッファリングされた外部結果セットから行をフェッチするループでも、より多くのクエリを実行できます。

または mysqli_result::fetch_all() は、結果セット全体をPHP配列として返します。その後、その配列をループできます。

ストアドプロシージャの呼び出しは特殊なケースです。ストアドプロシージャには複数の結果セットが返される可能性があるため、それぞれに独自の行セットがある場合があるためです。 @ a1ex07からの回答がmysqli_multi_query()の使用とmysqli_next_result()に結果セットがなくなるまでループすることについて言及しているのはこのためです。ストアドプロシージャに単一の結果セットがある場合でも、これはMySQLプロトコルを満たすために必要です。


PS:ところで、階層を表すデータがあるので、ネストされたクエリを実行しているようです。より簡単にデータを照会できるように、データの格納方法を変えることを検討してください。私はこのタイトル SQLとPHPを使用した階層データのモデル に関するプレゼンテーションを行いました。このトピックについては、私の本の章でも説明しています SQLアンチパターン:データベースプログラミングの落とし穴を回避する


CodeIgnitor 3.0.3でmysqli_next_result()を実装する方法は次のとおりです。

system/database/drivers/mysqli/mysqli_driver.php変更の262行目

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にアップデートし、このハックを新しいバージョンにコピーする必要がありました。

39
Bill Karwin

単に、mysqli_free_resultが呼び出された後、mysqli_next_result($ db)を呼び出す必要があります。

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

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

ストアドプロシージャによる以前の接続の保持を閉じる必要があります。毎回接続を閉じる代わりに、単に次のように使用できます:

mysqli_next_result($conn);
1
Salman Mohammad