• 締切済み

MySQL・Tomcat・JSP 何度もSubmit実行すると、SQLNestedExceptionエラー

現在、社内で勉強がてら、社内用アプリケーションを開発しております。 環境は以下です。 ・Windows2003ServerR2 ・Apache2.2.11 ・Tomcat6 ・MySQL5.1 ・Java1.6 フレームワークを使わずに、JSP/サーブレットで開発しております。 submitして、ブラウザの「戻る」を何度も繰り返したりして DB接続するサーブレットを何度も実行すると 「SQLNestedException」エラーになり、 サーバーリブート(もしくはtomcat/mysqlサービス再起動) しない限り、アプリに接続できなくなってしまいます。 tomcatのstdout.logには、以下が出力されております。 -------------------------------------------------------↓ org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object at org.apache.tomcat.dbcp.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:104) at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource.java:880) ・ ・ ・ -------------------------------------------------------↑ connectionのclose()をすれば良いようなことが、 ネットで調べてあったのですが、 射た感じの情報が 見つからなかったので、投稿させていただきました。 SJC-Pのバージョン5.0を取ってはいますが、 元々NotesDominoの開発が長く、JSPは初心者で、 申し訳ありません。 ご教示いただけるとありがたいです。 【補足】 すみません。try{}catchのcatch側に、close()を入れてませんでした。 しかし、close()を入れてないからといってサーバリブート(サービスリブート)しないかぎり、鍵が開けられないような感じになっているのは なんか変ですね。 引き続き調べてみますが、解る方いらっしゃいましたら、よろしくお願いいたします。 他力本願かもですが、生産性向上思考で、情報ご提供お願いいたします。

みんなの回答

回答No.7

携帯ブラウザの×を押されても、一定期間たてばセッションタイムアウトでsessionDestroyedメソッドが呼ばれるのではないでしょうか?(多分) 例えPCのブラウザでも電源をいきなり切れば同じ事です。 セッションタイムアウトは一定時間操作しなければ発生します。 コネクション数の上限とタイムアウトの時間を何分とるかです。

  • gigamac
  • ベストアンサー率57% (8/14)
回答No.6

これは正攻法では無いと思うのですが、ブラウザを閉じた時や、別の ページを表示した時の方法の一例として取扱いください。 JavaScriptを用い、onUnloadイベントが発生した時に、セッションや コネクションを削除するサーブレットを呼び出す方法です。 --------------- <SCRIPT language="JavaScript"> <!-- function byeWin(){ document.form1.closeWin.value = "true"; document.form1.submit(); } //--> </SCRIPT> <body onUnload="byeWin()"> <form action="hoge" method="POST" name="form1"> <input type="hidden" name="closeWin" value=""> ・・・ </form> --------------- サーブレット側にて、 --------------- String closeWin = request.getParameter("closeWin"); if( closeWin.equals("true") ){ // セッション、コネクション削除 HttpSession session = request.getSession(true); Connection con = (Connection)session.getAttribute("con"); if( con != null){ con.close(); } session.invalidate(); } ・・・ --------------- という感じでしょうか。 (つっこみ所は多々ありますが、実際にシステムで使用してます) ただし、携帯電話ではダメでしょうし、ブラウザ等、環境によっては NGかもしれませんし、あくまでも一例として。

fushululu
質問者

お礼

すみません。補足の方に書いちゃいました。

fushululu
質問者

補足

お忙しい中、回答ありがとうございます。 参考にさせていただきます。 もともと作ろうとしているものが、 ケータイからもアクセス可能なシステムなので、 ケータイブラウザ側の対応も考えたいのですが、 ケータイサイトでDBを使用しているサービスは多々ありますし、 何かしらの対処の方法があると思いますので、 がんばって探してみます。 最悪、毎日リブート運用とか、バッチを仕込むのも考えます。 もし、何か方法が見つかりましたら、情報提供くださるとありがたいです。

  • gigamac
  • ベストアンサー率57% (8/14)
回答No.5

すみません。No4の回答ですが、ブラウザを閉じた事を検知するのは 少々、コツがいるようです。 今、ちょっとしたサンプルが見つからない為、見つかりましたら、 提示したいと思います。

fushululu
質問者

お礼

ご回答ありがとうございます。 無償でお仕事を依頼しているようで、大変恐縮です。 セッションがメモリ上からガベージされるタイミングで呼ばれるなら、 セッションリスナーでいけそうな感じがしましたが。 私の方でも色々調べてみます。 万が一見つかりましたら、 情報いただけるとありがたいです。

  • gigamac
  • ベストアンサー率57% (8/14)
回答No.4

セッションリスナーをご存知でしょうか? http://www.ingrid.org/jajakarta/servletapi/servletapi-4.0/docs-ja/javax/servlet/http/HttpSessionListener.html セッション作成時とか消滅時のタイミングで呼ばれます。 sessionDestroyedメソッドは消滅時に呼ばれます(ブラウザを閉じた時等) インターネットで検索すると幾つかサンプルが出てきますので詳細は そちらをご覧ください。 ご参考まで。

  • gigamac
  • ベストアンサー率57% (8/14)
回答No.3

この例外はDBCPのコネクションプールを受け持つメソッドで発生しています。 コネクションプールはリソースの省資源化、コネクションする際のサーバー負荷軽減などメリットがあります。 また、コネクションプールは通常、最大数が決まっています。 それをオーバーしてしまうとgetConnectionメソッドで、コネクションオブジェクトを返す事ができなくなり、 getConnectionメソッドはコネクションが空くまで(どこかのインスタンスでcloseされるまで)、待ち状態になります。 それが、ずーーーと続いてしまうとタイムアウトで例外発生という仕組みです。(恐らくcontext.xmlファイルのmaxWait設定値を超えたとき) セッションを作って管理するのが良いと思います。 1つの接続に対し、セッションオブジェクトを生成し、 そのセッションオブジェクト内にコネクションオブジェクトを 置いておく構造にします。そして、そのセッション内に コネクションオブジェクトがnullならgetConnectionするという 感じです。 若しくは、最初の画面からシステムの機能画面へ遷移する際に セッションをはり、getConnectionします。 そして、済んだ後、例えば最初の画面へ戻ったとき等に、 コネクションをcloseし、セッションを無効化する。 という事で、ご参考まで。

fushululu
質問者

お礼

皆様ご回答ありがとうございます。 初めて投稿するもので、あまりの回答の早さに驚いております。 セッションで管理するのがよさげなのですね。 ちょっとやってみます。 気になるのですが、ブラウザの「×」で閉じた場合、 セッションの破棄は「invalidate()」をされないと思うので、コネクションプールは開いたままになってしまうような気がするのですが。 ケータイでもアクセスできるようなシステムを作りたいと思ってまして、 その場合、JavaScriptのonUnloadでSubmitさせるとかはできないと思うので。 以下の2案のような対処方法があったらいいと思うのですが、なさそうですね。 ・バックグラウンドでコネクションプーリングを監視するJavaプログラムとかを常駐させといて、使われてなくて開いているコネクションプーリングがあったら閉じる ・getConnectionは新規にコネクションプールを取得するメソッドですので、getActiveConnectionみたいな、開いていて使われてないコネクションを取得するメソッドがあればいいのですが、APIリファレンスを見る限りなさそうですね。

  • askaaska
  • ベストアンサー率35% (1455/4149)
回答No.2

いやいやいや ずばりconnectionをcloseしていないのが原因よ。 データベースが接続を許可している数が 例えば50となっている場合、 connectionを50個ゲットしたら 次の51個目はゲットできないわ。 そうなると強制的にDBとのコネクションを切らない限り 次のコネクションを生成することができないのよ。

回答No.1

http://atbb.jp/kurimaru/viewtopic.php?p=39 ↑の状況に似てる気がします。 >今回は web アプリケーション側で、SQL を実行する度に > BasicDataSource クラスを毎回 new していたため、その都度新たな > JDBC 接続が生成され、プーリングされていた。 >つまり、sleep プロセスがたまる一方で、これが MySQL の max >connections を超えたとき Nested Exception が発生した、という >ことのよう。 DBの接続方法の部分のコードやJDBCドライバーは何を使っているのか? とかがあればもう少し原因がわかるかもしれず。 >【補足】 >すみません。try{}catchのcatch側に、close()を入れてませんでした。 >しかし、close()を入れてないからといってサーバリブート(サービスリブート)しないかぎり、鍵が開けられないような感じになっているのは >なんか変ですね。 そんなことはないでしょう、世の中1つの問題が複数のインシデントを引き起こしたりするもんです。

関連するQ&A