- PR -

セッションに登録したコネクションオブジェクトの接続プールへの返却方法について

投稿者投稿内容
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-08-28 16:22
―――――――――――――――――――――――――――――――――――
【開発環境】
統合開発環境:Eclipse2.0.2
JDK: j2sdk1.4.1_03
フレームワーク: Struts1.1rc1(MVC形式)
Webサーバ: Apache1.3.28
サーブレットコンテナ: Tomcat4.0.6
DBサーバ: MiracleLinux2.1
DB: Oracle9i
接続プール:javax.sql.DataSourceを利用
―――――――――――――――――――――――――――――――――――

現在ストラッツを用いたWEBアプリケーション開発をやっています。

DBのテーブルの情報をJDBC経由で取得して
ブラウザに表の形式で表示します。その際
テーブルの情報を、たとえば、一頁に20件分の結果セットを
返すみたいな感じに切り分けしてページングして表示したい。
それを実現する方法として、
 
コネクションオブジェクトを取得
   ↓
   ステートメントの設定
   ↓
     問合せ
   ↓ 
 ResultSetオブジェクトを取得
   ↓
   結果をBeanに格納
   ↓
    ブラウザに表示
 
という流れで、
コネクションおよびResultSetをセッションに登録し、
ページングする際に一頁分ごとにデータをResultSetオブジェクトからメソッド
( next()、previous()、first()、last() )を使い取り出し、
その結果をBeanに格納し最終的にブラウザに表示させる。
コネクションはプールしておき、ひとつのセッションごとに
割り当て、セッションが終了した時点でクローズする。
WEBアプリケーション自体はMVCにそって作成しているので、
 
M(ビジネスロジック)▼
 コネクションオブジェクトの取得〜結果をBeanに格納

V(ビュー)▼
 画面表示
 
と切り分けてやっています。
この場合、クライアント側(ブラウザ)で表示をみている時に
クライアントのPCがなんらかの理由でダウンしてしまうと、
コネクションがクローズされずに残ってしまい、リソースを
無駄にしてしまいます。そいった状況に陥らないように
するためには、そのようなケースが発生した場合、
どのようにしてコネクションをクローズしたらよいのでしょうか?

セッションのタイムアウト時に
javax.servlet.http.HttpSessionBindingListenerインターフェイスを
利用して処理を行わせようとしましたが、
その際にセッションの情報からコネクションオブジェクト
をとりだし、それをクローズとしたかったのですが、
下記ソースのコネクションをセッションから抜き出す操作のところで
プログラムがうんともすんともうごかない状態になってしまいます。
エラーかともおもったんですが、エラーを出力していないので
ちがうみたいです。。

public void valueUnbound (HttpSessionBindingEvent event) {

 HttpSession hs = event.getSession();
Connection conn = (Connection) hs.getAttribute("conn");
if (conn != null) {
 try {
 conn.close();
}catch (SQLException sqle) {
System.err.println(sqle.getMessage());
}
 conn = null;
}
 System.out.println("valueUnBound");
}

コーディングを間違えているようには思えないんですが
原因が分らないのでどなたか原因がお分かりでしたら
ご指摘お願いします。

もしくはページングを行う方法でもっとよい別のやり方が
あるのでしょうか?
taku
ぬし
会議室デビュー日: 2002/11/12
投稿数: 918
お住まい・勤務地: 墨田区→中野区
投稿日時: 2003-08-28 16:53
引用:

忍者鳥取県さんの書き込み (2003-08-28 16:22) より:
コーディングを間違えているようには思えないんですが
原因が分らないのでどなたか原因がお分かりでしたら
ご指摘お願いします。

もしくはページングを行う方法でもっとよい別のやり方が
あるのでしょうか?


 コーディングを間違えているというより、根本的におかしくないですか?
コネクションをセッションに登録して使いまわしちゃいけませんよ。
コネクションプーリングへのコネクションの返却って、
各リクエスト毎に行うものですよ。
クライアントアプリケーションなら、
DBの接続はアプリケーションが終了するまで、
接続を維持したままで問題ありませんが、
WEBアプリケーションでそんなことをして大丈夫だと思われますか?
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-08-28 17:19
takuさん はじめまして。早速のレスありがとうございます。

実際まだ私のほうのJAVAの経験が浅くて、
(JAVAと言うかこの業界事態の経験が・・(・_・; )>(冷汗) )
調べ調べやっているためおかしなことを聞くことがあるかもしれませんが
ご容赦ください。

>コーディングを間違えているというより、根本的におかしくないですか?
>コネクションをセッションに登録して使いまわしちゃいけませんよ。
>コネクションプーリングへのコネクションの返却って、
>各リクエスト毎に行うものですよ。
>クライアントアプリケーションなら、
>DBの接続はアプリケーションが終了するまで、
>接続を維持したままで問題ありませんが、
>WEBアプリケーションでそんなことをして大丈夫だと思われますか?

 Webアプリケーションでコネクションプールを行うと
 具体的にどのような不具合が生じるのでしょうか?
 もし、なんらかの不具合が生じるとするならば、
 Webアプリケーションで多量なデータをDBから検索し、ブラウザに
 ページングして表示する際には、ページングを行うごとに

 接続プールからコネクション取得→ 再度ステートステートメント取得 →
 問合せ → ResultSetオブジェクト取得

 といった操作を行うのが正攻法なんでしょうか?
 たびたびselect文を投げるのもDBに多量のデータが存在する場合は
 パフォーマンスが悪くなるように思うのですが、、、
 もし、一般的に使われているもっとよい方法があればご教示お願いします。
 m(_ _)mペコリンコ




[ メッセージ編集済み 編集者: 忍者鳥取県 編集日時 2003-09-09 16:35 ]
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2003-08-28 18:12
引用:

忍者鳥取県さんの書き込み (2003-08-28 17:19) より:
> Webアプリケーションでコネクションプールを行うと
 具体的にどのような不具合が生じるのでしょうか?



ここでの「コネクションプール」というのは、セッションオブジェクトのコネクション
オブジェクトを格納する、ということでしょうか。そうではなくて通常の「コネクション
プーリング」であれば問題ないです。

ご質問の状況で、まず心配になるのは

・各セッションがコネクションを独占することによるコネクションの枯渇
・検索対象のレコードに対するReadロックを解除しないために更新・削除がブロックされる

ことです。これらは問題ないのでしょうか。

引用:

 もし、なんらかの不具合が生じるとするならば、
 Webアプリケーションで多量なデータをDBから検索し、ブラウザに
 ページングして表示する際には、ページングを行うごとに

 接続プールからコネクション取得→ 再度ステートステートメント取得 →
 問合せ → ResultSetオブジェクト取得

 といった操作を行うのが正攻法なんでしょうか?



そのとおりです。

引用:

 たびたびselect文を投げるのもDBに多量のデータが存在する場合は
 パフォーマンスが悪くなるように思うのですが、、、



経験上それほどでもないです。が、selectとselectの間で挿入・削除などがあった場合に
表示にずれが生じることがあることが問題になるかもしれません。

引用:

 もし、一般的に使われているもっとよい方法があればご教授お願いします。



JDK1.4とOracle 9iの組み合わせならjavax.sql.RowSetインタフェースが使うのが良い
かもしれません。
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-08-28 19:32
引用:

ご質問の状況で、まず心配になるのは

・各セッションがコネクションを独占することによるコネクションの枯渇
・検索対象のレコードに対するReadロックを解除しないために更新・削除がブロックされる

ことです。これらは問題ないのでしょうか。



・コネクションの枯渇についてですが、ピーク時の接続数を最大接続数に設定
 しているので問題ないと思います。(コネクションを500までプールする設定)

・オラクルでのロックというのは更新時に行単位にかかるもので、行の更新中に
  検索処理を行っても、読取の一貫性という機能により待たされると言う事はない。
  という風な認識があるのですが、Readロックという風に読み込み中にもロック
  がかかるといったことがおこるのでしょうか?
  
引用:

経験上それほどでもないです。が、selectとselectの間で挿入・削除などがあった場合に
表示にずれが生じることがあることが問題になるかもしれません。



 ・表示にずれが生じても、システム上問題ないと思いますので、
  そのあたりは大丈夫だと思います。

引用:

JDK1.4とOracle 9iの組み合わせならjavax.sql.RowSetインタフェースが使うのが良い
かもしれません。



 教えて頂いたjavax.sql.RowSetについて調査してみます。
 お忙しいところ、ご親切にありがとうございます。


uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2003-08-28 19:50
引用:

忍者鳥取県さんの書き込み (2003-08-28 19:32) より:
・オラクルでのロックというのは更新時に行単位にかかるもので、行の更新中に
  検索処理を行っても、読取の一貫性という機能により待たされると言う事はない。
  という風な認識があるのですが、Readロックという風に読み込み中にもロック
  がかかるといったことがおこるのでしょうか?  



OracleではREADロックは発生しませんね。失礼しました。

[ メッセージ編集済み 編集者: uk 編集日時 2003-08-28 20:21 ]
Hush
会議室デビュー日: 2002/04/23
投稿数: 13
投稿日時: 2003-08-28 20:09
引用:

・コネクションの枯渇についてですが、ピーク時の接続数を最大接続数に設定
 しているので問題ないと思います。(コネクションを500までプールする設定)



最大同時利用者数というのが、何を指していっているのか分からないんで、はっきりとしたことはいえないのですが、コネクションプールの数を最大同時利用者数に合わせたとしても、コネクションが枯渇しないとは言い切れませんよ。

Httpセッションは基本的にはタイムアウトするまで破棄されません。明示的に破棄することも可能ですが、そのためには利用者からの明示的に何らかのアクションが必要で、それを利用者に強制することはできません。つまり、必ずログアウトするとは限らないと言うことです。したがってWebアプリへの接続とブラウザの終了を繰り返すような操作をした場合、実際の利用者数よりも多くのHttpセッションが存在するような状況になることは、十分考えられます。

つまりDBへのコネクションをHttpセッションに紐付けるようなことをした場合、最大同時利用者数よりもDBへのコネクションが多く必要になる可能性は十分に考えられます。

したがって、通常WebアプリケーションでDBのコネクションをセッションに保持するような手段は取らないほうが賢明だと考えられます。
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-08-28 20:56
引用:

最大同時利用者数というのが、何を指していっているのか分からないんで、はっきりとしたことはいえないのですが、コネクションプールの数を最大同時利用者数に合わせたとしても、コネクションが枯渇しないとは言い切れませんよ。



説明が足りなくてすみませんでした。
ピーク時の接続数とは、私が現在開発しているWebアプリケーション
では特定の時間にアクセスが集中します。そのときの接続数のことです。
最大接続数とは、プログラマー側で設定する接続プールできる最大の
コネクションの数のことです。

引用:

Httpセッションは基本的にはタイムアウトするまで破棄されません。明示的に破棄することも可能ですが、そのためには利用者からの明示的に何らかのアクションが必要で、それを利用者に強制することはできません。つまり、必ずログアウトするとは限らないと言うことです。したがってWebアプリへの接続とブラウザの終了を繰り返すような操作をした場合、実際の利用者数よりも多くのHttpセッションが存在するような状況になることは、十分考えられます。
つまりDBへのコネクションをHttpセッションに紐付けるようなことをした場合、最大同時利用者数よりもDBへのコネクションが多く必要になる可能性は十分に考えられます。



たしかにおっしゃる通りだと思います。セッションを破棄されるには
セッションのタイムアウト、もしくはユーザがアクションを起こす必要があると
思います。
 ユーザーのアクションについてですが、ブラウザを閉じるといった動作ぐらい
だったらJAVAスクリプトでウィンドウが閉じられるといったイベントを
感知して、そのイベントをもとにセッションを閉じることは可能だと思います。
私が問題としているのはユーザ側のPCが急にダウンした際にイベントを感知できない
のでセッションのタイムアウト時になんらかの処理を施して、コネクションが
クローズできないかと言うことなのです。ユーザ側のPCが急にダウンするといった
事象自体、そうそう頻度が高く発生するとこととは思えないので、セッションのタイムアウト時に、コネクションのクローズの処理を行えれば十分対応できるのではないかと考えます。

スキルアップ/キャリアアップ(JOB@IT)