PHP/MySQLiで2つの準備されたステートメントを使用して、mysqlデータベースからデータを取得しています。ただし、ステートメントを実行すると、「コマンドが同期していません。現在コマンドを実行できません」というエラーが表示されます。
これが私のコードです:
$stmt = $mysqli->prepare("SELECT id, username, password, firstname, lastname, salt FROM members WHERE email = ? LIMIT 1";
$stmt->bind_param('s', $loweredEmail);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($user_id, $username, $db_password, $firstname, $lastname, $salt);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
while($mysqli->more_results()){
$mysqli->next_result();
}
$stmt1 = $mysqli->prepare("SELECT privileges FROM delegations WHERE id = ? LIMIT 1");
//This is where the error is generated
$stmt1->bind_param('s', $user_id);
$stmt1->execute();
$stmt1->store_result();
$stmt1->bind_result($privileges);
$stmt1->fetch();
私が試したこと:
コードの使用:
while($mysqli->more_results()){
$mysqli->next_result();
}
//To make sure that no stray result data is left in buffer between the first
//and second statements
PS:「Out of Sync」エラーは、2番目のステートメントの「$ stmt1-> error」から発生します
Mysqli :: queryでMYSQLI_USE_RESULTを使用すると、mysqli_free_result()を呼び出さない限り、以降のすべての呼び出しでエラーコマンドが返されます
複数のストアドプロシージャを呼び出すと、「コマンドが同期していません。このコマンドを現在実行できません」というエラーが発生する可能性があります。これは、呼び出し間で結果オブジェクトに対してclose()関数を使用する場合でも発生する可能性があります。この問題を修正するには、ストアドプロシージャを呼び出すたびに、mysqliオブジェクトのnext_result()関数を呼び出すことを忘れないでください。以下の例をご覧ください。
<?php
// New Connection
$db = new mysqli('localhost','user','pass','database');
// Check for errors
if(mysqli_connect_errno()){
echo mysqli_connect_error();
}
// 1st Query
$result = $db->query("call getUsers()");
if($result){
// Cycle through results
while ($row = $result->fetch_object()){
$user_arr[] = $row;
}
// Free result set
$result->close();
$db->next_result();
}
// 2nd Query
$result = $db->query("call getGroups()");
if($result){
// Cycle through results
while ($row = $result->fetch_object()){
$group_arr[] = $row;
}
// Free result set
$result->close();
$db->next_result();
}
else echo($db->error);
// Close connection
$db->close();
?>
これが役に立てば幸い
「コマンドが同期していません。このコマンドは現在実行できません」
このエラーの詳細は、mysqlのドキュメントに記載されています。これらの詳細を読むと、同じ接続で別の準備済みステートメントを実行する前に、準備済みステートメント実行の結果セットを完全にフェッチする必要があることが明らかになります。
問題の修正は、ストア結果の呼び出しを使用して実行できます。これは私が最初にやろうとしていたことの例です:
<?php
$db_connection = new mysqli('127.0.0.1', 'user', '', 'test');
$post_stmt = $db_connection->prepare("select id, title from post where id = 1000");
$comment_stmt = $db_connection->prepare("select user_id from comment where post_id = ?");
if ($post_stmt->execute())
{
$post_stmt->bind_result($post_id, $post_title);
if ($post_stmt->fetch())
{
$comments = array();
$comment_stmt->bind_param('i', $post_id);
if ($comment_stmt->execute())
{
$comment_stmt->bind_result($user_id);
while ($comment_stmt->fetch())
{
array_Push($comments, array('user_id' => $user_id));
}
}
else
{
printf("Comment statement error: %s\n", $comment_stmt->error);
}
}
}
else
{
printf("Post statement error: %s\n", $post_stmt->error);
}
$post_stmt->close();
$comment_stmt->close();
$db_connection->close();
printf("ID: %d -> %s\n", $post_id, $post_title);
print_r($comments);
?>
上記の場合、次のエラーが発生します。
コメントステートメントエラー:コマンドが同期していません。現在、このコマンドは実行できません
PHP通知:未定義の変数:error.phpの41行目のpost_title ID:9033->配列()
これが正しく機能するために必要なことは次のとおりです。
<?php
$db_connection = new mysqli('127.0.0.1', 'user', '', 'test');
$post_stmt = $db_connection->prepare("select id, title from post where id = 1000");
$comment_stmt = $db_connection->prepare("select user_id from comment where post_id = ?");
if ($post_stmt->execute())
{
$post_stmt->store_result();
$post_stmt->bind_result($post_id, $post_title);
if ($post_stmt->fetch())
{
$comments = array();
$comment_stmt->bind_param('i', $post_id);
if ($comment_stmt->execute())
{
$comment_stmt->bind_result($user_id);
while ($comment_stmt->fetch())
{
array_Push($comments, array('user_id' => $user_id));
}
}
else
{
printf("Comment statement error: %s\n", $comment_stmt->error);
}
}
$post_stmt->free_result();
}
else
{
printf("Post statement error: %s\n", $post_stmt->error);
}
$post_stmt->close();
$comment_stmt->close();
$db_connection->close();
printf("ID: %d -> %s\n", $post_id, $post_title);
print_r($comments);
?>
上記の例について注意すべき点がいくつかあります。
The bind and fetch on the statement still works correctly.
Make sure the results are freed when the processing is done.
正しいことを行い、準備されたステートメントでストアドプロシージャを使用する人のために。
何らかの理由で、ストアドプロシージャで出力変数をパラメーターとして使用すると、mysqliはリソースを解放できません。これを修正するには、出力変数/パラメーターに値を格納する代わりに、プロシージャの本体内でレコードセットを返すだけです。
たとえば、SET outputVar = LAST_INSERT_ID();の代わりにSELECT LAST_INSERT_ID();を使用できます。それからPHPで私はこのような戻り値を取得します:
$query= "CALL mysp_Insert_SomeData(?,?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("is", $input_param_1, $input_param_2);
$stmt->execute() or trigger_error($mysqli->error); // trigger_error here is just for troubleshooting, remove when productionizing the code
$stmt->store_result();
$stmt->bind_result($output_value);
$stmt->fetch();
$stmt->free_result();
$stmt->close();
$mysqli->next_result();
echo $output_value;
これで、「コマンドが同期していません。コマンドを実行できません」というエラーが発生することなく、2番目のストアドプロシージャを実行する準備ができました。レコードセットで複数の値を返す場合は、次のようにループしてすべてをフェッチできます。
while ($stmt->fetch()) {
echo $output_value;
}
ストアドプロシージャから複数のレコードセットを返す場合(複数の選択がある場合)、$ stmt-> next_result();を使用してそれらのレコードセットをすべて確認してください。