PreparedStatement IN句の代替案は?質問する

PreparedStatement IN句の代替案は?質問する

SQL インジェクション攻撃のセキュリティ上の問題により、複数の値がサポートされていない のINインスタンスを含むSQL 句を使用する場合の最善の回避策は何ですか。1 つのプレースホルダーは、値のリストではなく、1 つの値を表します。java.sql.PreparedStatement?

次の SQL ステートメントを検討してください。

SELECT my_column FROM my_table where search_column IN (?)

使用することは、本質的には、そもそもpreparedStatement.setString( 1, "'A', 'B', 'C'" );使用の理由を回避するための機能しない試みです。?

どのような回避策がありますか?

ベストアンサー1

利用可能なさまざまなオプションの分析と、それぞれの長所と短所については、Jeanne BoyarskyのJDBC での SELECT ステートメントのバッチ処理JavaRanch Journal のエントリ。

推奨されるオプションは次のとおりです。

  • 準備しSELECT my_column FROM my_table WHERE search_column = ?、各値に対して実行し、クライアント側で結果を UNION します。必要な準備済みステートメントは 1 つだけです。遅くて面倒です。
  • 準備しSELECT my_column FROM my_table WHERE search_column IN (?,?,?)て実行します。IN リストのサイズごとに 1 つの準備されたステートメントが必要です。高速でわかりやすいです。
  • 準備しSELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ...て実行します。[または、UNION ALLセミコロンの代わりに を使用します。 --ed] IN リストのサイズごとに 1 つの準備されたステートメントが必要です。非常に遅く、 よりも明らかに悪いためWHERE search_column IN (?,?,?)、ブロガーがなぜこれを提案したのかわかりません。
  • ストアド プロシージャを使用して結果セットを構築します。
  • IN リストのサイズに関する N 種類のクエリ (たとえば、2、10、50 個の値を持つ) を準備します。6 個の異なる値を持つ IN リストを検索するには、サイズ 10 のクエリを次のように入力しますSELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6)。適切なサーバーであれば、クエリを実行する前に重複する値を最適化して除去します。

これらのオプションはどれも理想的ではありません。

JDBC4とそれをサポートするサーバーを使用している場合、最善の選択肢はx = ANY(y)PreparedStatement.setArrayボリスの答え

setArrayただし、IN リストで動作させる方法はないようです。


場合によっては、SQL ステートメントが実行時に読み込まれますが (たとえば、プロパティ ファイルから)、可変数のパラメータが必要になります。このような場合は、まずクエリを定義します。

query=SELECT * FROM table t WHERE t.column IN (?)

次に、クエリをロードします。次に、実行する前にパラメータの数を決定します。パラメータ数がわかったら、次を実行します。

sql = any( sql, count );

例えば:

/**
 * Converts a SQL statement containing exactly one IN clause to an IN clause
 * using multiple comma-delimited parameters.
 *
 * @param sql The SQL statement string with one IN clause.
 * @param params The number of parameters the SQL statement requires.
 * @return The SQL statement with (?) replaced with multiple parameter
 * placeholders.
 */
public static String any(String sql, final int params) {
    // Create a comma-delimited list based on the number of parameters.
    final StringBuilder sb = new StringBuilder(
        String.join(", ", Collections.nCopies(possibleValue.size(), "?")));

    // For more than 1 parameter, replace the single parameter with
    // multiple parameter placeholders.
    if (sb.length() > 1) {
        sql = sql.replace("(?)", "(" + sb + ")");
    }

    // Return the modified comma-delimited list of parameters.
    return sql;
}

JDBC 4 仕様を介して配列を渡すことがサポートされていない特定のデータベースの場合、このメソッドは、低速の句条件= ?をより高速なIN (?)句条件に変換することを容易にし、その後、メソッドを呼び出すことによって拡張することができますany

おすすめ記事