27

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

現在、init()関数で接続を開き、 で閉じるだけですdestroy()

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

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

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

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

4

9 に答える 9

22

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

ソリューションの問題点

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

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

接続プールを使用する理由

接続プールには多くの利点がありますが、何よりも問題を解決します。

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

いつ接続を取得するか

サービス デリゲート (doPost、doGet、doDisco など) で開始されたコール スタックのどこかで、接続を取得してから、正しいことを行い、finally ブロックでそれを返す必要があります。finallyC# のメイン アーキテクトが、ブロックの 100 倍以上のブロックを使用する必要があると以前に言ったことに言及しておく必要がありcatchます。語られたことのない真実の言葉...

どの接続プール

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

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

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

于 2009-05-25T16:27:51.203 に答える
14

私は Commons DBCP の使用に反対です。接続プールを管理するには、コンテナに任せる必要があります。

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

于 2008-10-27T22:57:02.213 に答える
4

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

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

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

于 2008-10-27T21:40:31.057 に答える
2

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

それが邪魔にならなくなったら、ジョンが提案したように、必要な限り接続を開いたままにしてください.

于 2008-10-27T21:35:02.177 に答える
2

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

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

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

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

于 2008-10-27T21:35:23.173 に答える
1

それをプールします。

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

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

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

于 2008-10-27T23:35:04.617 に答える
1

データベース接続は、必要な間だけ開いたままにしておく必要があります。これは、おそらくdoGet/doPostメソッドの範囲内で何をしているかによって異なります。

于 2008-10-27T21:31:30.500 に答える
1

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

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

BR、
~A

于 2008-10-27T22:15:53.873 に答える
0

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

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

于 2008-10-27T21:35:49.977 に答える