6

私はこのコードを手に入れました:

// Some starting variables
$test = new mysqli("localhost","root","","testdatabase");
$Query = array();
$Query[] = "SELECT 'wos' FROM items WHERE itemID = 3";
$Query[] = "SELECT 'wos' FROM items WHERE itemID";
$Query[] = "SELECT 'wos' FROM items WHERE itemID = 5";
$Query = implode(";",$Query);
$Errors = array();

// Execute multi query

if ($test->multi_query($Query)) {
  do {
    // fetch results
    $Result = $test->store_result();
    print_r($Result);
    if($test->errno === 0) {
          echo $Result->num_rows . "<br>";
    }
    else {
        $Errors[] = $test->error;
    }
    $Result->close();
    
    if (!$test->more_results()) {
      break;
    }
    if (!$test->next_result()) {
      $Errors[] = $test->error;
      break;
    }
  } while (true);
}

ご覧のとおり、X 個の後続のクエリがあり、それらすべてを実行したいと考えています。したがって、クエリ 2 が失敗した場合は、マルチクエリを続行して、次のクエリを実行したいと考えています。これどうやってするの?

また、エラーが発生した場合は、このエラーを に保存したいと考えています$Errors。ただし、現在、エラーメッセージのみを保存でき、対応するクエリは保存できないため、意図したとおりに機能していません。失敗したクエリがなければ、エラー メッセージだけではあまり役に立ちません。だから私は次のようなものが欲しい: "Query 3 failed ('SELECT ...'): 'ERROR MESSAGE'".

これはどのように可能ですか?を使用してループ内の現在のエラーを取得できますが、の$test->errorようなものはありません$test->currentsubsequentquery。どうやってやるの?

4

2 に答える 2

1

ここでの問題は、MySQL プロトコルの制限と呼ばれるものです。マルチ クエリを使用する場合 (MySQL の観点から: マルチ ステートメント オプションを [オン] に設定してからクエリを送信)、サーバーはこれを分割し、次々に実行します。回答は、オリジンを参照せずに送信されます。クライアント (この場合は PHP/mysqli) が、エラーがどの実際のステートメントに関連しているかを把握できる唯一の方法は、完全なクエリ文字列を解析し、何らかのマッピングを試みる必要があります。しかし、多くの場合、これは機能しません。一部のステートメントは、特にCALL1 つのステートメントにマップできない複数の結果セットを返す可能性があります。

エラーについて詳しく知りたい場合は、次の 2 つの選択肢があります。

醜いものは行って$Query = implode(";\n\n",$Query);おり、提供された行のエラーメッセージを解析し、それらを一致させます。

または単に multi_query を使用しないでください。multi_query は、複数の結果セットを返すストアド プロシージャ コールを処理するためのものです。上記のような場合に multi_query を使用すると、サーバーは次のクエリ コマンドを待たずに次のクエリを直接処理できるため、ほんのわずかな待ち時間しか節約できませんが、mysqlnd の非同期クエリ操作を使用することで到達できます。

于 2013-01-10T15:29:46.973 に答える
-1

1 つのステートメントで複数のクエリを実行することは、一般的にはお勧めできません。優れた SQL クライアント (PDO など) では、複数のクエリをまったく許可しません。これは、SQL インジェクションがはるかに困難になるためです。あなたの考えを思いとどまらせ、次の解決策のいずれかを提案したいと思います。

  • 3 つの単一ステートメントを使用する
  • 3 つのクエリは非常に似ているため、準備済みステートメントを使用し、異なるパラメーター バインディングで 3 回実行する必要があります。これにより、3 つの単一ステートメントよりもパフォーマンスが向上し、SQL インジェクションが不可能になります。
  • 次のような 1 対 1 のクエリを設計するか、UNION を使用して何かを行うことができます。

    "SELECT 'wos' FROM items WHERE itemID IN ('3', '5')"
    

「こいつは何を言っているんだ?これはもうアトミックじゃないだろう」と思ったら。次に、トランザクションを使用する必要があります...

于 2013-01-10T15:32:57.650 に答える