1

データベースに頻繁にアクセスするポートレットを開発しています。ユーザー入力に対する反応としてフィルタリングの可能性を提供する方法でクエリを指定する必要があります。フィルタリングに使用されるパラメーターは現在 2 つですが、この数は将来的に増える可能性があります。

現時点では、私の構築はすべての入力に対して非常にうまく機能しますが、準備されたステートメントを使用せず、クエリを手動で構築するだけなので、正しい/効果的な方法でそれを行っているとは思いません。

これは私のコードの例です(serviceFilterはarrayListで、typeFlagはStringです)

private String prepareQuery() {
        String query = "SELECT * from messages ";

        // check filters
        if (!typeFlag.equals("ALL")) {
            if (typeFlag.equals("XML")) {
                query += "WHERE type='" + TYPE_XML + "'";
            } else {
                query += "WHERE type='" + TYPE_JAVA + "'";
            }
        }

        // lets see if user specifies some service filtering
        if (serviceFilter.size() > 0) {
            if (!typeFlag.equals("ALL")) {
                query += " AND (";
            } else {
                query += " WHERE (";
            }

            for (int i = 0; i < serviceFilter.size(); i++) {
                if (i>0) {
                    query += " OR ";
                }
                String service = serviceFilter.get(i);
                System.out.println("Filter: " + service);
                query += "sender='" + service + "' OR receiver='" + service + "'";
            }
            query += ")";
        }

        query += " ORDER BY id DESC LIMIT " + String.valueOf(limit);

        System.out.println(query);

        return query;
    }

最初の問題は、SQL インジェクションを防ぐ方法がないことです (すべての入力がチェックボックスとスクロールバーから来ているため、ユーザーは実際には何も入力しないため、それほど大きな問題にはなりません)。私のarrayListの人口は非常に長く、クエリごとに変化する可能性があるため、ここで準備済みステートメントを使用する方法がわかりません。

この事実により、クエリ自体が非常に長くなる可能性があります。以下は、引数が 2 つだけのクエリの例です (20 項目の場合を想像してください)。

SELECT * from messages  WHERE (sender='GreenServiceESB#GreenListener' OR receiver='GreenServiceESB#GreenListener' OR sender='queue/DeadMessageQueue' OR receiver='queue/DeadMessageQueue') ORDER BY id DESC LIMIT 50

基本的に、私の質問は次のとおりです。これはクエリを作成する効果的な方法ですか (おそらくそうではありません)。どのようなアプローチをお勧めしますか?

PS:何らかの形で重要な場合は、JDBCを使用してdbに接続し、クエリを実行しています...

ヒントをありがとう!

4

2 に答える 2

1

まず第一に、あなたはあなたの問題の1つをほのめかしました - を使用していませんPreparedStatement. ユーザー入力を受け取り、それを SQL ステートメントで直接使用すると、サイトが SQL インジェクション攻撃を受けやすくなります。

あなたが望んでいるのはこれだと思います:

select * from (
  select *, row_number over (order by id_desc) as rowNum
  from messages
  where sender in (?,?,?,?,?,?,?,?) --8, 16 or however many ?'s you'll need
    or receiver in (?,?,?,?,?,?,?,?)
) results
where rowNum between (1 and ?)
order by rowNum

ここで、ユーザー入力が何であれパラメーターをバインドし、演算子に余分なスポットが残っている場合は、またはINなどのテーブルに存在できない (またはおそらく存在しない) 値にそれらをバインドします。任意の数の値をサポートする必要がある場合は、クエリを複数回実行し、メモリ内の結果を自分で並べ替えます。nullHiMom#2$@

関数に関する限りrow_number、それはMySQLでは機能しない可能性があります(私はMySQLの専門家ではありません)が、同等のものがあります(または、limitパラメータ化可能である可能性があります。わかりません.

于 2013-06-03T09:24:02.243 に答える
1

次のようなものを使用したい場合

  create.selectFrom(BOOK)
  .where(PUBLISHED_IN.equal(2011))
  .orderBy(TITLE)

それ以外の

  SELECT * FROM BOOK
  WHERE PUBLISHED_IN = 2011
  ORDER BY TITLE

http://www.jooq.org/を見ることができます。コードを簡素化し、「if (something) { sql += " WHERE ..." }」のようなことを避けることができます。これはアンチパターンであり、可能な場合は使用しないでください。

于 2013-06-03T08:09:35.873 に答える