2016-01-02 9 views
6

データベースにログメッセージを書き込むクラスがあるとします。このクラスはコードのさまざまな部分から呼び出され、同じINSERT文を繰り返し実行します。 PreparedStatementを使用するよう呼びかけているようです。PreparedStatementの正しい使い方

しかし、私はそれの正しい使い方が不思議です。メソッドを呼び出すたびに新しいPreparedStatementを作成した場合でも、クラスメンバーとしてPreparedStatementを保持し、決して閉じる必要はない場合でも、実行するたびに同じ実行パスを使用するDBMSのように、DBMSを使用する利点はありますかそれを再利用して利益を得るためには?

このシナリオでPreparedStatementを使用して利益を得る唯一の方法は、クラスメンバーとして開かれた状態を維持することだけです。同じ接続でPreparedStatementの異なるクエリを同時に開くことができますか?これらのPreparedStatementのうちの2つが同時に実行されるとどうなりますか? JDBCドライバはPreparedStatementの実行を待ち行列に入れていますか?

ありがとうございます。 Dani。

+2

これは、使用しているDBMSによって異なります。いくつかは(自動的に)実行プランをキャッシュします。ドライバーの中には計画をキャッシュしていないものもあります。 –

+0

ミドルウェアは、前のコメントに加えて、ステートメントもキャッシングすることができます(アプリケーションサーバーなど)。 –

+1

JDBC接続は一般にスレッドセーフではないため、同じ接続上で同時に(異なるスレッドから)2つのPreparedStatementを実行しないでください。試してみると奇妙なエラーが発生します。 – Jesper

答えて

3

私が知り、経験した限り、文は1つの接続では並行して実行されません。あなたが正しく観察したように、PreparedStatementは、それらが作成されたConnectionにバインドされています。

ロギングコール(1回に1つの挿入とロックオーバーヘッド)を同期させたくない場合は、このロギングステートメント用に予約された接続を維持する必要があります。

しかし、1つのステートメントだけに専用のプールを持つことは非常に無駄に思えます。それもやりたくありません。

どのようなオプションが残っていますか?

  • すべての挿入に関するステートメントを準備します。データベースにデータを送るI/O操作があるので、準備のオーバーヘッドは比較的小さいです。

  • 新しい接続の作成時にプール内の文を準備し、後で参照するためにMap <Connection,PreparedStatement>を作成します。新しい接続の作成を少し遅くしますが、文をリサイクルすることができます。

  • があなたのログをキューイングするためにいくつかの非同期道(JMS)を使用して、メッセージ駆動型Beanまたは類似

内部バッチおそらくいくつかのより多くのオプションとして挿入を行います - しかし、それは私が今考えることができるすべてです。

幸いです。

+0

こんにちは1月Tksあなたの返信です。私はあなたの最初のオプション、各呼び出し(私の現在の実装)のための1つのPreparedStatementに固執すると思います、ちょうど私はPreparedStatementの必要性を見ません。私は単純な文で全体のクエリを実行する感じが速くなければなりません。 DBMSがPreparedStatementをキャッシュしている場合は、何らかのステートメントを繰り返しキャッシュする必要があります。 –

+0

まったく反対です。 Stringに値を入れると、ステートメントは繰り返されません。バインド変数(= PreparedStatement)を使用して行うことSQLInjectionはもちろん、アプリケーションの外部から文字列を「ログ」する場合に発生する可能性のある – Jan

関連する問題