まず、クライアントとサーバーのプリペアドステートメントを区別することが重要です。
クライアントが準備したステートメント
クライアントのプリペアドステートメントは、「エミュレートされた」プリペアドステートメントです。これは、SQLステートメント文字列がクライアント側でトークン化され、実行のためにステートメントをサーバーに送信する前に、プレースホルダーがリテラル値に置き換えられることを意味します。完全なSQLステートメントは、実行のたびにサーバーに送信されます。一般ログを使用して、これがどのように機能するかを調べることができます。例:
次のコード:
ps=conn.prepareStatement("select ?")
ps.setInt(1, 42)
ps.executeQuery()
ps.setInt(1, 43)
ps.executeQuery()
ログに表示されます:
255 Query select 42
255 Query select 43
「クエリ」は、プロトコルレベルで、COM_QUERY
コマンドは、次のステートメント文字列とともに送信されます。
サーバープリペアドステートメント
サーバーのプリペアドステートメントは「真の」プリペアドステートメントです。つまり、クエリテキストがサーバーに送信され、解析され、プレースホルダーと結果の情報がクライアントに返されます。これは、useServerPrepStmts=true
を設定したときに得られるものです。 。ステートメント文字列は、COM_STMT_PREPARE
を使用してサーバーに1回だけ送信されます。 電話(文書化されたここ
)。各実行は、COM_STMT_EXECUTE
を送信することによって実行されます プリペアドステートメントハンドルと、プレースホルダーの代わりに使用するリテラル値を使用します。
クライアントが準備した例とは対照的に、同様のコードブロックを使用できます(ただし、今回はサーバーが準備したステートメントを有効にします):
ps2=conn2.prepareStatement("select ?")
ps2.setInt(1, 42)
ps2.executeQuery()
ps2.setInt(1, 43)
ps2.executeQuery()
そして、ログには次のように表示されます:
254 Prepare select ?
254 Execute select 42
254 Execute select 43
ステートメントが実行される前に準備されていることがわかります。ログは私たちに好意を示し、実行の完全なステートメントを示していますが、実際には、実行ごとにプレースホルダー値のみがクライアントからサーバーに送信されます。
プリペアドステートメントのキャッシュ
多くの接続プールは、接続の使用全体でプリペアドステートメントをキャッシュします。つまり、conn.prepareStatement("select ?")
を呼び出すと 、同じPreparedStatement
を返します 同じステートメント文字列を使用した連続呼び出しのインスタンス。これは、トランザクション間で接続がプールに返されるときに、サーバー上で同じ文字列を繰り返し準備することを回避するのに役立ちます。
MySQLJDBCオプションcachePrepStmts
この方法で準備されたステートメント(クライアントとサーバーの両方で準備されたステートメント)をキャッシュし、ステートメントの「準備可能性」をキャッシュします。 MySQLには、サーバー側で準備できないステートメントがいくつかあります。ドライバーは、サーバー上でステートメントの準備が可能であると判断した場合はその準備を試み、準備が失敗した場合は、クライアントが準備したステートメントにフォールバックします。このチェックは、サーバーへのラウンドトリップが必要なため、コストがかかります。このオプションは、このチェックの結果もキャッシュします。
これがお役に立てば幸いです。