1. ホーム
  2. java

[解決済み] PreparedStatementのIN句の選択肢は?

2022-03-14 17:04:57

質問

SQLを使用する際の回避策を教えてください。 IN のインスタンスで java.sql.PreparedStatement これは、SQL インジェクション攻撃のセキュリティ上の問題から、複数の値に対してサポートされていません。1つの ? プレースホルダーは、値のリストではなく、ひとつの値を表します。

次のようなSQL文を考えてみましょう。

SELECT my_column FROM my_table where search_column IN (?)

使用方法 preparedStatement.setString( 1, "'A', 'B', 'C'" ); を使用する理由を回避しようとする試みは、本質的にうまくいきません。 ? を使用します。

どのような回避策があるのでしょうか?

解決方法は?

様々な選択肢と、それぞれの長所・短所を分析したものが公開されています こちら .

推奨されるオプションは以下の通りです。

  • 準備 SELECT my_column FROM my_table WHERE search_column = ? を実行し、その結果をクライアントサイドでUNIONする。プリペアドステートメントを1つだけ必要とする。遅くて辛い。
  • 準備 SELECT my_column FROM my_table WHERE search_column IN (?,?,?) を作成し、それを実行する。size-of-IN-listごとに1つのプリペアドステートメントを必要とする。高速で明白。
  • プリペア SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ... を作成し、実行する。[または UNION ALL をセミコロンの代わりに使ってください。--ed] のようになります。size-of-IN-listごとに1つのprepared statementを必要とする。バカみたいに遅く、厳密には WHERE search_column IN (?,?,?) このブログ主はなぜそれを提案したのでしょうか?
  • 結果セットを構築するためにストアドプロシージャを使用する。
  • N 個の異なる size-of-IN-list クエリ (たとえば、2、10、50 の値) を準備します。6つの値を持つIN-listを検索するには、size-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-listで動作しますが。


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 メソッドを使用します。