アプリ版:「スタンプのみでお礼する」機能のリリースについて

メモリリーク(?)時にSQLException

初めて質問させていただきます。

java+mysqlでWebアプリを作成しているのですが、DBからデータ取得後、取得結果をStringに格納するところで2回に1回だけエラーとなってしまいます。

具体的には下記のようなプログラム実行時にSQLExceptionが出てしまいます。

// ---- プログラム
// ・・・(略)・・・
String str = "";
rs = pst.executeQuery();
while (rs.next())}
str = str + rs.getString("name");
}

// ---- 出力されるエラー(途中まで)
java.sql.SQLException: Operation not allowed after ResultSet closed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:910)
at com.mysql.jdbc.ResultSet.checkClosed(ResultSet.java:644)
at com.mysql.jdbc.ResultSet.next(ResultSet.java:6663)

ResultSetがクローズされてるよというエラーだと思うのですが、
str = str + rs.getString("name");
のところを
str = rs.getString("name");
に書き換えた場合と、String型ではなくStringBufferでappendを使って文字列連結させていった場合はエラーになりません。
また、ログを入れて動作状況を確認してみたところwhile文は何回かは動いているようです。
※while文は5000回以上ループし、strは最終的にかなり大きいサイズになります。

このような状況を考えると、メモリリークが発生して落ちているのかと思うのですが、発生しているエラー内容は上記の通りSQLExceptionです。
また、一番腑に落ちないのはこのエラーが2回に1回だけ出る、ということです。

同じような現象をご存知の方がいらっしゃいましたら、何が起こっているのか教えていただけないでしょうか?

未熟ながら私の予想ですと、メモリリークが発生する前にjavaがGCでメモリクリアしようとしているんだけど、そのときにResultSetも一緒に消しちゃってる・・・?
javaやjdbcのバグ???とも考えているのですが、どうやって確認したらいいのかわからず困っています。

A 回答 (5件)

java のgcがResultSetを消しちゃうと言う様な話は、聞いた事がありませんが、


ResultSet自体が、時間切れや、過負荷時に、自動的にクローズされると言う
事なら、ありえるかと思います。
ResultSet自体の実装として、TCP/IP等による、ソケット接続を内部的に行っ
ている可能性がありますからねぇ。
    • good
    • 0
この回答へのお礼

>ResultSet自体が、時間切れや、過負荷時に、自動的にクローズされると言う
>事なら、ありえるかと思います。
なるほど。
1/2の確立でしかエラー発生しないことを考えると可能性としては低い気もしますが、その線で調べてみます。ありがとうございます!

お礼日時:2010/02/09 09:13

> 変数rsは使う前に毎回初期化していますので、問題ないかと思います。



どう初期化しているのかわからないけど
「~思います」がついているうちは疑ってかかるわよ。
私はResultSetの使い方を疑っているわ。
closeされた後のResultSetに対し何かやっているんじゃないか、ってね。
そのひとつが変数rsの再利用だったわけ。

もう一度、なにか思い込みでやっているところがないか
見直してみるべきよ。
    • good
    • 0

PreparedStatementを使い回ししている可能性はありませんか?



参考URLより:
デフォルトでは、Statement オブジェクトごとに 1 つの ResultSet オブジェクトだけが同時にオープンできます。

rsやpstがスレッドセーフでは無いのに、他のスレッドから(他のリクエストから)サーブレットが呼ばれていませんか?

参考URL:http://java.sun.com/javase/ja/6/docs/ja/api/java …
    • good
    • 0

このコードだけじゃわからないけど


他の回答者とは別の視点から仮説。

変数rsを同じスレッド内で再利用していない?
    • good
    • 0
この回答へのお礼

変数rsは使う前に毎回初期化していますので、問題ないかと思います。
回答ありがとうございます。

お礼日時:2010/02/16 09:34

>while (rs.next())


rsはResultSetクラスですかね。java.sql のクラスは使ったことがないけど、
Iteratorを実装しているなら、次が有るかどうかは、hasnext() でチェックして、
次があれば、ifブロック内で next() でobject を得て作業という手順のはず。
次があるかのチェックもしないで、next() を繰り返せば、当然いつかは、「データを得られなかった → Operation not allowed after ResultSet closed」というエラーになる。

この回答への補足

回答ありがとうございます。
また、説明不足で申し訳ありません。ご指摘の通り、rsはResultSetです。
しかし、ResultSetはnext()で次が無かったらfalseを返すので、
>while (rs.next())
は問題ないかと思います。
ご指摘にあるように「いつか必ずエラーになる」のではなく、2回に1回のみエラーになっています。

補足日時:2010/02/08 18:26
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!