web-dev-qa-db-ja.com

Javaサーブレットのデータベース接続を管理するための最良の方法

Javaサーブレットでデータベース接続を管理するための最良の方法は何ですか?

現在、私はinit()関数で接続を開き、destroy()で閉じます。

ただし、データベース接続を「永続的に」保持することは悪いことかもしれないと私は心配しています。

これはこれを処理する正しい方法ですか?そうでない場合、いくつかのより良いオプションは何ですか?

編集:もう少し明確にするために:リクエストごとに新しい接続を開いたり閉じたりするだけで試しましたが、テストでは、作成する接続が多すぎるためにパフォーマンスの問題が発生しました。

複数のリクエストで接続を共有することに価値はありますか?このアプリケーションの要求はほとんどすべて「読み取り専用」であり、かなり迅速に送信されます(要求されるデータはかなり小さいですが)。

27
TM.

私は実際にCommonsDBCPの使用に同意しません。接続プーリングを管理するには、実際にはコンテナに任せる必要があります。

Javaサーブレットを使用しているので、これはサーブレットコンテナで実行することを意味し、私が精通しているすべての主要なサーブレットコンテナは接続プール管理を提供します(JavaEE仕様も必要です)。コンテナがたまたまDBCPを使用している場合(Tomcatが使用しているように)、それ以外の場合は、コンテナが提供するものを使用してください。

14
Jack Leow

誰もが言うように、接続プールを使用する必要があります。どうして?どうした?等。

ソリューションの何が問題になっていますか

昔々いいアイデアだと思っていたので知っています。問題は2つあります。

  1. すべてのスレッド(サーブレットリクエストはそれぞれ1つのスレッドで処理されます)は同じ接続を共有します。したがって、リクエストは一度に1つずつ処理されます。単一のブラウザに座ってF5キーを使用した場合でも、これは非常に低速です。試してみてください。これは高レベルで抽象的なように聞こえますが、経験的でテスト可能です。
  2. 何らかの理由で接続が切断された場合、initメソッドは再度呼び出されません(サーブレットがサービスを停止しないため)。 doGetまたはdoPostにtry-catchを入れてこの問題を処理しようとしないでください。そうすると、地獄に陥ります(質問されることなくアプリサーバーを作成するようなものです)。
  3. 考えられることとは逆に、トランザクションの開始は接続だけでなくスレッドに関連付けられるため、トランザクションに問題はありません。私は間違っているかもしれませんが、これはとにかく悪い解決策なので、汗を流さないでください。

接続プールを選択する理由

接続プールには多くの利点がありますが、ほとんどの場合、接続プールは次の問題を解決します。

  1. 実際のデータベース接続を確立するにはコストがかかります。接続プールには常にいくつかの追加の接続があり、そのうちの1つを提供します。
  2. 接続が失敗した場合、接続プールは新しい接続を開く方法を知っています
  3. 非常に重要です。すべてのスレッドが独自の接続を取得します。これは、スレッドが本来あるべき場所、つまりDBレベルで処理されることを意味します。 DBは非常に効率的で、同時リクエストを簡単に処理できます。
  4. 他のもの(JDBC接続文字列の場所を一元化するなど)ですが、これには何百万もの記事や本などがあります

接続を取得するタイミング

サービスデリゲート(doPost、doGet、doDiscoなど)で開始されたコールスタックのどこかで接続を取得し、正しいことを実行して、finallyブロックで返す必要があります。 C#のメインアーキテクトの男が、finallyブロックの100倍以上のcatchブロックを使用する必要があると一度言ったことに言及する必要があります。本当の言葉は決して話されませんでした...

どの接続プール

サーブレットを使用しているため、コンテナが提供する接続プールを使用する必要があります。 JNDIコードは、接続の取得方法を除いて、完全に正常です。私の知る限り、すべてのサーブレットコンテナには接続プールがあります。

上記の回答に関するコメントの一部は、代わりに特定の接続プールAPIを使用することを提案しています。 WARは移植可能で、「展開するだけ」である必要があります。これは基本的に間違っていると思います。コンテナによって提供される接続プールを使用する場合、アプリは複数のマシンにまたがるコンテナにデプロイ可能であり、Java EE仕様が提供するすべての凝ったものです。はい、コンテナ固有のデプロイメント記述子を作成する必要がありますが、それはEEの方法です。

あるコメント提供者は、特定のコンテナー提供の接続プールがJDBCドライバーで機能しないと述べています(彼/彼女はWebsphereについて言及しています)。それは完全にとてつもなくばかげているように聞こえるので、おそらく本当です。そのようなことが起こったら、「やるべきこと」をすべてゴミ箱に捨てて、できることは何でもしてください。それは私たちが支払われるものです、時々:)

22
Dan Rosenstark

Commons DBCP を使用します。これは、接続プールを管理するApacheプロジェクトです。

DoGetまたはdoPostで接続を取得してクエリを実行し、finallyブロックで接続を閉じます。 (con.close()はそれをプールに返すだけで、実際には閉じません)。

DBCPは、接続タイムアウトを管理し、それらから回復できます。データベースが一定期間ダウンした場合の現在の方法では、アプリケーションを再起動する必要があります。

4
ScArcher2

接続をプールしていますか?そうでない場合は、接続を開いたり閉じたりするオーバーヘッドを減らす必要があります。

それが邪魔にならないようになったら、ジョンが提案したように、必要な限り接続を開いたままにしておきます。

2
Jack Leow

最良の方法は、現在Googleでより良いリファレンスシートを探しているところですが、プールを使用することです。

初期化時に、データベースへのX個のSQL接続オブジェクトを含むプールを作成します。これらのオブジェクトは、ArrayListなどのある種のリストに格納します。これらの各オブジェクトには、「isLeased」のプライベートブール値があります。これは、最後に使用された時間と接続です。接続が必要なときはいつでも、プールから接続を要求します。プールは、isLeased変数をチェックして最初に使用可能な接続を提供するか、新しい接続を作成してプールに追加します。必ずタイムスタンプを設定してください。接続が完了したら、プールに戻すだけで、isLeasedがfalseに設定されます。

常に接続がデータベースを拘束しないようにするために、プールをときどき通過して、接続が最後に使用された時刻を確認するワーカースレッドを作成できます。十分な長さがある場合は、その接続を閉じてプールから削除できます。

これを使用する利点は、Connectionオブジェクトがデータベースに接続するのを待つ時間が長くないことです。すでに確立されている接続は、好きなだけ再利用できます。また、アプリケーションのビジー状態に基づいて接続数を設定できます。

2
Joel

それをプールします。

また、生のJDBCを実行している場合は、Connection、PreparedStatementなどの管理に役立つものを調べることができます。非常に厳しい「軽量」要件がない限り、たとえば、SpringのJDBCサポートを使用すると、コードが単純化されます。多く-そしてあなたはSpringの他の部分を使用することを強制されません。

ここでいくつかの例を参照してください:

http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html

1
alex

データベース接続は、必要な間だけ開いたままにしておく必要があります。これは、実行している内容に応じて、おそらくdoGet/doPostメソッドの範囲内にあります。

1
John Topley

データソースに関連付けられた接続プールでうまくいくはずです。サーブレットリクエストメソッド(doget/dopostなど)のdataSourceから接続を取得できます。

dbcp、c3p0、および他の多くの接続プールは、探していることを実行できます。接続をプールしているときに、StatementsとPreparedStatementsをプールすることをお勧めします。また、指定したようにREAD HEAVY環境の場合は、ehcacheなどを使用して結果の一部をキャッシュすることをお勧めします。

BR、
〜A

1
anjanb

通常、リクエストごとに接続を開く方が管理しやすいことがわかります。つまり、サーブレットのdoPost()またはdoGet()メソッドにあります。

Init()で開くと、すべてのリクエストで利用できるようになります。同時リクエストがあるとどうなりますか?

0