質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.52%

  • Java

    13773questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

JavaでSQL接続時に例外が発生する

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 861

syabon

score 3

前提・実現したいこと

DBに接続して読み書きする際に、このクラスだけで接続から切断までの処理を一括で行いと考えています。
他のクラスから利用する際、connect → sql実行 → close だけのシンプルな処理にしたいのです。
ResultSetがclose後に取得出来ないのは分かるのですが、それを回避する方法が分かりません。

発生している問題・エラーメッセージ

重大: null
java.sql.SQLException: Operation not allowed after ResultSet closed
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
    at com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:743)
    at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:6301)
    at dao.DbConnection.main(DbConnection.java:99)

該当のソースコード(質問後に修正しています。)

public class DbConnection {
    private Connection con;
    private Statement stmt;
    private ResultSet result;

    private String url = "jdbc:mysql://localhost:3306/database?useSSL=false";
    private String drv = "com.mysql.jdbc.Driver";
    private String id = "root";
    private String pass = "";

    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }

    public DbConnection(){
        try {
            con = DriverManager.getConnection(url, id, pass);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public ResultSet executeQuery(String sql){
        if(con != null){
            try{
                stmt = con.createStatement();
                result = stmt.executeQuery(sql);
            }catch(SQLException ex){
                return null;
            }
        }
        return result;
    }

    public int executeUpdate(String sql){
        int i = 0;
        if(con != null){
            try{
                stmt = con.createStatement();
                i = stmt.executeUpdate(sql);
            }catch(SQLException ex){
                System.out.print(ex.getLocalizedMessage());
                return -1;
            }
        }
        return i;
    }

    public boolean close(){
        try{
            stmt.close();
            con.close();
        }catch(SQLException ex){
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    public static void main(String[] args){

        try {
            DbConnection con = new DbConnection();
            Cart cart = new Cart();
            ResultSet result = con.executeQuery("SELECT * FROM PRODUCTS");
            while(result.next()){
                Product p = new Product(result.getInt(1),result.getString(2),result.getString(3),result.getString(4));
                cart.addItem(p,10);
            }
            con.close();        //StatementとConnectionをクローズ
            con.result.close(); //ResultSetをクローズ(不要になった時点で閉じる)
            cart.show();

        } catch (SQLException ex) {
            Logger.getLogger(DbConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

例外が発生しているのはcloseのところではなく、mainメソッド内のnext()を呼んでいるところですよね。これは、例外になります。

ResultSetというのは、問い合わせ結果を全部保持しているわけではないと考えてください。だからArrayListみたいなオブジェクトとはちょっと違うのです。
ではどういうオブジェクトなのかというと、DBから順次飛んでくる結果を受け取るバッファです。100件や1000件のデータなら結果は一瞬で取れるでしょうが、DBの仕事は数千万件、数十億件といったデータを扱うこと。そういうデータは取り出そうにも一瞬では取り出せませんし、結果として取り出すために全部メモリに格納しようとしたらメモリが足りません。
だから、DBが結果を出力し始めたらアプリも先頭から順次処理していくということができないといけず、その窓口がResultSetなのです。

ResultSetからデータを読み出す前に窓口であるResultSetを閉じてしまっては、もう読み出せなくて当然です。もしやりたいような「シンプルな」クラスインターフェースにしたいなら、ResultSetからArrayListにデータを全部抜き出してからcloseしてArrayListを返す形にしてみてください。無論、前述のような巨大データには対応できないプログラムになります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/20 23:31

    ご回答ありがとうございます。
    DbConnection クラスを使う側で閉じるように修正しましたが、これでよいのでしょうか。

    キャンセル

  • 2017/01/20 23:43

    良さげに見えます。

    キャンセル

  • 2017/01/20 23:45

    ありがとうございます!!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Java

    13773questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。