web-dev-qa-db-ja.com

いつステートメントの代わりにPreparedStatementを使用する必要がありますか?

PreparedStatementを使用する利点を知っています。

  • クエリはデータベースサーバーによって書き直され、コンパイルされます
  • sQLインジェクションに対する保護

しかし、Statementの代わりにそれをいつ使用するかを知りたいですか?

28
Johanna
  1. クエリはデータベースサーバーによって書き換えられ、コンパイルされます。

    準備済みステートメントを使用しない場合、データベースサーバーはステートメントを実行するたびに解析し、ステートメントの実行プランを計算する必要があります。同じステートメントを(異なるパラメーターを使用して)複数回実行する場合は、ステートメントを1回準備し、その準備したステートメントを再利用する価値があります。データベースアドホックにクエリを実行している場合、これによるメリットはおそらくほとんどありません。

  2. SQLインジェクションから保護

    これはほとんどの場合に必要な利点であり、そのため常にPreparedStatementを使用することをお勧めします。これは、クエリをパラメータ化する必要があるためですが、クエリをより安全に実行できます。これが役に立たないと思うのは、アドホックデータベースクエリを許可する場合だけです。アプリケーションのプロトタイプを作成してすばやく処理する場合、またはクエリにパラメーターが含まれていない場合は、Statementオブジェクトを使用するだけです。

27
Martin Booth

トムに尋ねる 意見

JDBCでのステートメントの使用は、BIND VARIABLESを受け入れることができない唯一のステートメントタイプであるため、DDL(ALTER、CREATE、GRANTなど)に使用するように100%ローカライズする必要があります。

他のすべてのタイプのステートメント(DML、クエリ)には、PreparedStatementsまたはCallableStatementsを使用する必要があります。これらは、バインド変数を受け入れる文のタイプであるためです。

これは事実であり、ルールであり、法律です。準備されたステートメントをどこでも使用してください。 STATEMENTSを使用する場所はほとんどありません。

彼は特にOracleについて話しているが、同じ原則が実行プランをキャッシュするどのデータベースにも当てはまる。

SQLインジェクション攻撃を同時に拡大および防止するデータベースアプリですか?欠点は何ですか?

17
mattjames

私はこのラウンドを回します:パブリックに配布されたアプリでは、一般的にalways準備されたステートメントを使用してください本当に説得力のある理由がない限りであり、常にパラメーターを提供する必要があります "準備されたステートメントに適切に」であり、クエリ文字列にスプライスするのではありません。

どうして?まあ、基本的にあなたが与えた理由(または少なくとも2番目のもの)のために...

9
Neil Coffey

PreparedStatementsは、WHERE句で非常に注意深く使用する必要があります。

テーブルが次のように定義されているとします。

create table t (int o, k varchar(100), v varchar(100))

(例:「o:オブジェクトID(外部キー)、k:属性キー、v:属性値」)。

さらに、vには(一意でない)インデックスがあります。

create index ixt on t ( v )

このテーブルに次のように挿入された2億行が含まれているとします。

for (i = 0; i < 100*1000*1000; i++) {
  insert into t (o,k,v) values (i,'k1','v1');
  insert into t (o,k,v) values (i,'k2', Convert(i, varchar));
}

(「したがって、すべてのオブジェクトoには属性k1 = v1およびk2 = oがあります」)

次に、次のようなクエリを作成しないでください。

select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k=? and tx.v=? and ty.k=? and ty.v=?

(「指定された2つの属性を持つオブジェクトを見つける」)

OracleとMSSQLの私の経験は、それらのクエリが必要とする可能性があるということです 何分 戻ります。これは、where句に一致する行がない場合でも当てはまります。 SQL Serverが最初にtx.vまたはty.vを検索するかどうかに依存します。

1つの文書では、列kおよびvの値をステートメントに直接入力します。これは、SQL-Serverが実行計画を計算するときに値を考慮に入れているためだと思います。

次のようなクエリは、常にミリ秒後に返されます。

select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k='k1' and tx.v='v1' and ty.k='k2' and ty.v='1234'

( "SQL-Serverは常に最初にv = '1234'を検索し、次にv = 'v1'を検索します")

よろしく
ウルフギャング

5
Wolfgang

Statment(select、insert、update、delete)の代わりにいつでもPreparedStatementを使用できます。パフォーマンスが向上し、SQLインジェクションから保護されます。

ただし、WHERE variable IN [ hundreds possibilities ]を使用したリクエストのような動的リクエストでは使用しないでください。

  1. これは逆効果です。新しいリクエストを毎回キャッシュするため、パフォーマンスとメモリが失われます。また、PreparedStatementはSQLインジェクション用だけではなく、パフォーマンスに関するものです。この場合、ステートメントは遅くなりません。

  2. あなたのプールにはPreparedStatmentの制限があります(-1デフォルトですが、制限する必要があります)。この制限に達します!制限がない場合や非常に大きな制限がある場合は、メモリリークのリスクがあり、極端な場合にはOutofMemoryエラーが発生します。したがって、3人のユーザーが使用する小規模な個人プロジェクトの場合は劇的ではありませんが、大企業でアプリが数千人と数百万のリクエストで使用されている場合は望ましくありません。

いくつかの読書。 IBM:準備されたステートメントのキャッシュによる定期的なOutOfMemoryエラー

1
amdev

ステートメント:SQLクエリが実行されるたびに、このSQLステートメントはコンパイルされるDBMSに送信されます。したがって、サーバーの負荷が増加し、パフォーマンスが低下します。

connection con=null; 
  String sql="select * from employee where id=5";
Statement st=conn.createStatement();

PreparedStatement:ステートメントとは異なり、PreparedStatementは作成時にパラメーターとしてSQLクエリを提供されます。

connection con=null; 
String sql="select * from employee where id=?";
PreparedStatement ps=conn.prepareStatement(sql);

このSQLステートメントはデータベースに送信され、そこでコンパイルされます。したがって、preparedStatementのコンパイルは1回だけ行われますが、ステートメントのコンパイルはStatementが呼び出されるたびに行われます。

1
stumbler

クエリを実行する場合はPreparedStatementを使用します。 (挿入、選択など...)。上に書かれた他の人と同じラソソン。

しかし、dynamic paramtersを使用する必要がある場合は、単純にStatementを使用します。これは、実行するよりも文字列SQLを簡単に構築できるためです。 (inmyopinion)prepareStatmentを使用して動的クエリを作成する場合、誰も理解できない巨大なスパゲッティコードが生成されます。

1
Farkas Csanád

SQLインジェクションの防止、フォーマットの移植性(Statementからは取得できません)、パフォーマンスが明白な理由です。ただし、PreparedStatementにはペナルティがありません。たとえば、オーバーヘッドがいくらかあるため、1回しか実行しない場合、一般にStatementよりも遅くなります。したがって、一般的な考え方はPreparedStatementは同じクエリを何度も実行するときに使用する必要があるということです。ただし、オーバーヘッドの程度はデータベースサーバーの実装によって異なります。そのため、パフォーマンスを考慮してPreparedStatementではなくStatementを選択するのは、特定のデータベースの実際の経験/実験に基づいています。サーバ。

0
bryantsai