Javaサーブレットでデータベース接続を管理するための最良の方法は何ですか?
現在、私はinit()
関数で接続を開き、destroy()
で閉じます。
ただし、データベース接続を「永続的に」保持することは悪いことかもしれないと私は心配しています。
これはこれを処理する正しい方法ですか?そうでない場合、いくつかのより良いオプションは何ですか?
編集:もう少し明確にするために:リクエストごとに新しい接続を開いたり閉じたりするだけで試しましたが、テストでは、作成する接続が多すぎるためにパフォーマンスの問題が発生しました。
複数のリクエストで接続を共有することに価値はありますか?このアプリケーションの要求はほとんどすべて「読み取り専用」であり、かなり迅速に送信されます(要求されるデータはかなり小さいですが)。
私は実際にCommonsDBCPの使用に同意しません。接続プーリングを管理するには、実際にはコンテナに任せる必要があります。
Javaサーブレットを使用しているので、これはサーブレットコンテナで実行することを意味し、私が精通しているすべての主要なサーブレットコンテナは接続プール管理を提供します(JavaEE仕様も必要です)。コンテナがたまたまDBCPを使用している場合(Tomcatが使用しているように)、それ以外の場合は、コンテナが提供するものを使用してください。
誰もが言うように、接続プールを使用する必要があります。どうして?どうした?等。
ソリューションの何が問題になっていますか
昔々いいアイデアだと思っていたので知っています。問題は2つあります。
接続プールを選択する理由
接続プールには多くの利点がありますが、ほとんどの場合、接続プールは次の問題を解決します。
接続を取得するタイミング
サービスデリゲート(doPost、doGet、doDiscoなど)で開始されたコールスタックのどこかで接続を取得し、正しいことを実行して、finallyブロックで返す必要があります。 C#のメインアーキテクトの男が、finally
ブロックの100倍以上のcatch
ブロックを使用する必要があると一度言ったことに言及する必要があります。本当の言葉は決して話されませんでした...
どの接続プール
サーブレットを使用しているため、コンテナが提供する接続プールを使用する必要があります。 JNDIコードは、接続の取得方法を除いて、完全に正常です。私の知る限り、すべてのサーブレットコンテナには接続プールがあります。
上記の回答に関するコメントの一部は、代わりに特定の接続プールAPIを使用することを提案しています。 WARは移植可能で、「展開するだけ」である必要があります。これは基本的に間違っていると思います。コンテナによって提供される接続プールを使用する場合、アプリは複数のマシンにまたがるコンテナにデプロイ可能であり、Java EE仕様が提供するすべての凝ったものです。はい、コンテナ固有のデプロイメント記述子を作成する必要がありますが、それはEEの方法です。
あるコメント提供者は、特定のコンテナー提供の接続プールがJDBCドライバーで機能しないと述べています(彼/彼女はWebsphereについて言及しています)。それは完全にとてつもなくばかげているように聞こえるので、おそらく本当です。そのようなことが起こったら、「やるべきこと」をすべてゴミ箱に捨てて、できることは何でもしてください。それは私たちが支払われるものです、時々:)
Commons DBCP を使用します。これは、接続プールを管理するApacheプロジェクトです。
DoGetまたはdoPostで接続を取得してクエリを実行し、finallyブロックで接続を閉じます。 (con.close()はそれをプールに返すだけで、実際には閉じません)。
DBCPは、接続タイムアウトを管理し、それらから回復できます。データベースが一定期間ダウンした場合の現在の方法では、アプリケーションを再起動する必要があります。
接続をプールしていますか?そうでない場合は、接続を開いたり閉じたりするオーバーヘッドを減らす必要があります。
それが邪魔にならないようになったら、ジョンが提案したように、必要な限り接続を開いたままにしておきます。
最良の方法は、現在Googleでより良いリファレンスシートを探しているところですが、プールを使用することです。
初期化時に、データベースへのX個のSQL接続オブジェクトを含むプールを作成します。これらのオブジェクトは、ArrayListなどのある種のリストに格納します。これらの各オブジェクトには、「isLeased」のプライベートブール値があります。これは、最後に使用された時間と接続です。接続が必要なときはいつでも、プールから接続を要求します。プールは、isLeased変数をチェックして最初に使用可能な接続を提供するか、新しい接続を作成してプールに追加します。必ずタイムスタンプを設定してください。接続が完了したら、プールに戻すだけで、isLeasedがfalseに設定されます。
常に接続がデータベースを拘束しないようにするために、プールをときどき通過して、接続が最後に使用された時刻を確認するワーカースレッドを作成できます。十分な長さがある場合は、その接続を閉じてプールから削除できます。
これを使用する利点は、Connectionオブジェクトがデータベースに接続するのを待つ時間が長くないことです。すでに確立されている接続は、好きなだけ再利用できます。また、アプリケーションのビジー状態に基づいて接続数を設定できます。
それをプールします。
また、生のJDBCを実行している場合は、Connection、PreparedStatementなどの管理に役立つものを調べることができます。非常に厳しい「軽量」要件がない限り、たとえば、SpringのJDBCサポートを使用すると、コードが単純化されます。多く-そしてあなたはSpringの他の部分を使用することを強制されません。
ここでいくつかの例を参照してください:
http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html
データベース接続は、必要な間だけ開いたままにしておく必要があります。これは、実行している内容に応じて、おそらくdoGet/doPost
メソッドの範囲内にあります。
データソースに関連付けられた接続プールでうまくいくはずです。サーブレットリクエストメソッド(doget
/dopost
など)のdataSourceから接続を取得できます。
dbcp、c3p0、および他の多くの接続プールは、探していることを実行できます。接続をプールしているときに、StatementsとPreparedStatementsをプールすることをお勧めします。また、指定したようにREAD HEAVY環境の場合は、ehcacheなどを使用して結果の一部をキャッシュすることをお勧めします。
BR、
〜A
通常、リクエストごとに接続を開く方が管理しやすいことがわかります。つまり、サーブレットのdoPost()またはdoGet()メソッドにあります。
Init()で開くと、すべてのリクエストで利用できるようになります。同時リクエストがあるとどうなりますか?