4

時々、可変数のログ行をデータベースに挿入するデータベース ログ アペンダがあります。

SQL インジェクションを防ぐ方法で SQL ステートメントを作成したいのですが、サーバー側の準備済みステートメントを使用しないでください (選択ごとに可変数の行があるため、それらをキャッシュしても効果はありませんが、ここではパフォーマンスが低下する可能性があります)。 .

また、プリペアード ステートメントの便利さも気に入っており、文字列連結よりもプリペアード ステートメントの方が好きです。「クライアント側の準備済みステートメント」のようなものはありますか?

4

6 に答える 6

7

最も単純なソリューションである準備済みステートメントのベンチマークを行っていないようです。「パフォーマンスが低下する可能性がある」とあなたは言いますが、実際にテストするまではわかりません。

私は間違いなく最初に準備されたステートメントをテストします。それらパフォーマンスをわずかに妨げたとしても、それらをテストするまで、必要なパフォーマンスを達成できるかどうかはわかりません。

最も明白なソリューションを試していないのに、代替ソリューションを見つけることに時間を費やす必要はありません。

準備されたステートメントの実行計画のキャッシュコストがかかることがわかった場合は、それをチューニングまたは無効にする DB 固有の方法があることに気付くかもしれません。

于 2009-08-06T13:15:38.317 に答える
2

まず、パフォーマンスが問題であると測定されるまで、最も明白な解決策を採用する必要があるというJonの答えは、一般的に確かに正しいアプローチです。

あなたのパフォーマンスの懸念は見当違いではないと思います。私は確かに、プリコンパイルされた複雑なステートメントがパフォーマンススケールで劇的に失敗するのを見てきました(MS-SQL2000の場合)。その理由は、ステートメントが非常に複雑で、パラメーターに応じていくつかの潜在的な実行パスがあったためですが、コンパイルによって1つのパラメーターのセットがロックされ、次のパラメーターのセットが遅すぎたため、再コンパイルによって次の再計算が強制されました。さまざまなパラメータセットに適した実行プラン。

しかし、実際にそれを見るまで、その懸念は非常に遠いものです。

ここでの根本的な問題は、パラメーターのエスケープがデータベース固有であるということです。したがって、データベースのJDBCドライバーがこれを行うための非標準的なものを提供していない限り(ほとんどありません)、別のライブラリーまたは別のエスケープメカニズムが必要になります。この1つのデータベースに非常に固有です。

あなたの質問の言い回しから、あなたのパフォーマンスの懸念がまだそのような解決策を見つける(または開発する)ことに値するところまで来ていないように思えます。

また、JDBCドライバーがすべてこのように動作するわけではありませんが、技術的には、事前コンパイルはPreparedStatementオブジェクトにキャッシュされることになっているため、それを破棄して毎回新しいPreparedStatementを取得する必要はありません。実際には何かをキャッシュしているため、問題全体がミュートになっている可能性があり、特定のJDBCドライバーについて調査する必要があります。

仕様から:

INパラメータの有無にかかわらずSQLステートメントは、プリコンパイルして、PreparedStatementオブジェクトに格納できます。このオブジェクトを使用して、このステートメントを複数回効率的に実行できます。

于 2009-08-06T14:01:23.440 に答える
2

あなたの質問を正しく理解しているかどうかわかりません。PreparedStatementあなたのニーズに合わないものはありますか?

ステートメントがサーバー側にキャッシュされるかどうかは、データベース ドライバーと使用している特定のデータベースの実装の詳細だと思います。クエリ/ステートメントが時間の経過とともに変更された場合、これは影響を与えないはずです-キャッシュ/コンパイルされたステートメントは単に使用されません。

于 2009-08-06T13:15:14.637 に答える
0

次の疑似コードなど、通常の準備済みステートメントを使用することの何が問題になっていますか。

DatabaseConnection connection;
PreparedStatement insertStatement = ...;

    ...

connection.beginTransaction();
for (Item item : items)
{
   insertStatement.setParameter(1, item);
   insertStatement.execute();
}
connection.commitTransaction();

スマートなデータベース実装は、データベース サーバーとの 1 つの通信交換に複数の挿入をまとめます。

于 2009-08-06T13:35:46.730 に答える
0

準備済みステートメントを使用してはならない理由が思いつきません。接続プールを使用して J2EE サーバーでこれを実行している場合、サーバーは接続を開いたままにし、サーバーはアクセス/実行計画をキャッシュします。キャッシュするデータではありません。

毎回接続を閉じている場合は、パフォーマンスが向上していない可能性があります。ただし、SQL インジェクションを防止できます

ほとんどの Java パフォーマンス チューニングに関する書籍では、次のように説明されています。 Java パフォーマンス チューニング

于 2009-08-06T13:37:34.030 に答える
-1

準備済みステートメントは、クライアント側またはサーバー側を気にしません。

それらを使用して、SQL 文字列の連結を削除します。プリペアド ステートメントを使用しない理由は 1 つではありません。

于 2009-08-06T13:47:03.707 に答える