- ベストアンサー
WebSphere/DB2/ResultSet close/Exception
WebSphereを使って、Listenerで取得したデータソースを利用していますが、 String sql1 = "SELECT A1 FROM TEST1"; String sql2 = "SELECT B2 FROM TEST2 WHERE B1 = ?"; Connection conn = datasource.getConnection(); PreparedStatement ps1 = conn.preparedStatement(sql1); ResultSet rs1 = ps1.executeQuery(); while(rs1.next()){ PreparedStatement ps2 = conn.preparedStatement(sql2); ps2.setString(1,rs1.getString("A1")); ResultSet rs2 = ps2.executeQuery(); ps2.close(); } このロジックで、ps2をクローズすると、ps1で取得したResultSet rs1がクローズされるというExceptionが発生してしまいます。 (ループして戻ったときにrs1.next()でexceptionが起こる) なにか対処方法があるかご存知の方いらっしゃいましたら、よろしくお願いいたします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
申し訳ないです。いただいたExceptionでは少しもわかりませんでした。 ただ、ソースを見ないとなんともいえませんが、NO2さんがおっしゃるとおり呼び出し先でconnectionかstatementをcloseしている可能性がありそうですね。 脱線しますが…。 Java入門書などでBeanを作成する際に、そのBean内部でConnectionをcommit,closeするソースをよく見ます。 そのように作ってしまうと、トランザクション管理が出来なくなります。特にテーブル毎にBeanを作っていて複数のテーブルにinsert、updateなどするときは困ります。今回の場合それが問題かどうかはわかりませんからここまでにします。 >そっか。。まとめてpreparedStatementの配列を先に作っておいて、 >使うときに一個ずつとるようにすればよいのですね。でも最大ネスト数決まってしまうのはつらいかな。。。。って感じです。 『最大ネスト数が決まる』とはどのようなことを想定されているのでしょうか?申し訳ありません。 preparedStatementを使用することでつらいことってなかったものですから、アドバイスが間違って理解されると心配で…。
その他の回答 (2)
- pcbeginner
- ベストアンサー率46% (261/560)
サンプルの様に1度に実行するのではなく、 以下の様に分けてみてはどうでしょうか? ---------------------------------------- String sql1 = "SELECT A1 FROM TEST1"; String sql2 = "SELECT B2 FROM TEST2 WHERE B1 = ?"; Connection conn = datasource.getConnection(); PreparedStatement ps1 = conn.preparedStatement(sql1); ResultSet rs1 = ps1.executeQuery(); while(rs1.next()){ PreparedStatement ps2 = conn.preparedStatement(sql2); ps2.setString(1,rs1.getString("A1")); ResultSet rs2 = ps2.executeQuery(); ps2.close(); } String sql1 = "SELECT A1 FROM TEST1"; String sql2 = "SELECT B2 FROM TEST2 WHERE B1 = ?"; Connection conn = datasource.getConnection(); //まずSELECT A1 FROM TEST1の実行と結果の取得 PreparedStatement ps = conn.prepareStatement(sql1); ResultSet rs = ps.executeQuery(); ArrayList a1 = new ArrayList(); //sql1の実行結果格納用 while(rs.next()){ a1.add(rs.getString("A1")); } rs.close(); ps.close(); //次にSELECT B2 FROM TEST2 WHERE B1 = ?の実行と結果の取得 ps = conn.prepareStatement(sql2); ArrayList[] a2 = new ArrayList[a1.size()]; //sql2の実行結果格納用 for(int i = 0;i < a1.size();i++){ ps.setString(1,(String)a1.get(i)); rs = ps.exequteQuery(); a2[i] = new ArrayList(); while(rs.nest()){ a2[i].add(rs.getString("B2")); } rs.close(); } ps.close(); conn.close(); ---------------------------------------- また、 >実際には取得したBEANの結果によって、呼び出しクラスを変える処理になっています。 >呼び出されたクラス内でpreparedしていまして、必要であればさらにそのクラスが下位クラスを。。。という構成です。 とありますが、PreparedStatementやResultSetを参照渡ししていて、 呼び先でcloseしているため、呼び元で実行すると既にcloseされている ということはないでしょうか?
- braver_2004
- ベストアンサー率62% (20/32)
どのようなExceptionが出力されているのでしょうか。 差し支えなければ提示していただけると、詳しい回答ができるかもしれません。 関係ないかもしれませんが、一点だけアドバイスを。 while中のPreparedStatement をnewしていますが、もともとPreparedStatementはSQL文をプリコンパイルし、それを再利用することでSQLの文法チェックを最小にすることを可能にするものです。 ですので、 PreparedStatement ps2 = conn.preparedStatement(sql2); をwhileより前に、 ps2.close(); をwhileから抜けたあとにコーディングすると、パフォーマンスは向上します。 (このときrs2をcloseすることは忘れずに)
補足
>PreparedStatement ps2 = conn.preparedStatement(sql2); >をwhileより前に、 >ps2.close(); >をwhileから抜けたあとにコーディングすると、パフォーマンスは向上します。 ありがとうございます。 これは、サンプル用にこのように書いていますが、実際には取得したBEANの結果によって、呼び出しクラスを変える処理になっています。 呼び出されたクラス内でpreparedしていまして、必要であればさらにそのクラスが下位クラスを。。。という構成です。 そっか。。まとめてpreparedStatementの配列を先に作っておいて、 使うときに一個ずつとるようにすればよいのですね。でも最大ネスト数決まってしまうのはつらいかな。。。。って感じです。 尚、Exceptionの内容ですが、私としては全然差し支えはないのですが(笑)、デスクトップ環境と連携していなくて、USBメモリ接続も禁止されていたり、LANが基幹とつながっていなかったり(情報漏えい防止の関係)ので、手書きになってしまいますが、、、、 例外:javax.servlet.ServletExepetion: Invalid operation: result set closed at ~~~.servlet.TestServlet.executeService at ~~~.servlet.TestServlet.doService at ~~~.servlet.TestServlet.doGet at javax.servlet.http.HttpServlet.service at javax.servlet.http.HttpServlet.service at com.ibm.ws.webcontainer.servlet.servletWrapper.service at com.ibm.ws.webcontainer.servlet.servletWrapper.handleRequest (中略) at com.ibm.ws.util.TreeadPool$Worker.run ---- Begin backtrace for Nested Throwables com.ibm.db2.jcc.b.kf.lb(kf.java:3488) at com.ibm.db2.jcc.b.kf.c at com.ibm.db2.jcc.b.kf.next at com.ibm.ws.rsadapter.jdbc.WSJdbcResultSet.next at ~~~.servlet.TestServlet
お礼
IBMのSTSCサポートセンターに問い合わせをしたところ、 「同様の現象が確認できたので、こちらでも対応策を調査する」との事で、 その結果「WebSphereのリソース→JDBC→データソース→カスタムパラメータ→ResultSet Holdabilityの値を 2(デフォルト)から1にする事で対応できる」 ということでした。 2がコミット時にカーソルを閉じる 1がコミットされてもカーソルは保持する という設定です。 ResultSetを取得するようなSELECT文をWebSphereのJNIデータソース経由で実行すると、勝手にコミットしてしまってさらに全てのカーソルをクローズしているようです。 バグっぽい気がするんですが、一応これで対応できましたので、この質問はクローズすることにします ・・・・・と思ったんですが、しばらく置いておきます。 皆様のご意見をお聞きしたいので。