web-dev-qa-db-ja.com

JavaでResultSetが閉じられている例外を回避するにはどうすればよいですか?

コードがwhile(rs.next())ループに到達するとすぐに、ResultSet is closed例外が生成されます。この例外の原因と修正方法を教えてください。

編集:コード内で、while(rs.next())ループを別の(rs2.next())、両方の結果セットは同じDBからのものですが、これは問題ですか?

28
soldier.moth

最初のステートメントから結果セットを走査する前に、同じ接続で別のステートメントを実行したように聞こえます。同じデータベースからの2つの結果セットの処理をネストしている場合、何か間違ったことをしていることになります。これらのセットの組み合わせは、データベース側で行う必要があります。

49
Apocalisp

これは、使用しているドライバーなど、さまざまな理由で発生する可能性があります。

a)一部のドライバーは、ネストされたステートメントを許可しません。ドライバーがJDBC 3.0をサポートしているかどうかに応じて、Statementオブジェクトを作成するときに3番目のパラメーターを確認する必要があります。たとえば、FirebirdのJayBirdドライバーでも同じ問題がありましたが、postgresドライバーではコードは問題なく機能しました。次に、3番目のパラメーターをcreateStatementメソッド呼び出しに追加し、ResultSet.HOLD_CURSORS_OVER_COMMITに設定すると、コードがFirebirdでも正常に機能し始めました。

static void testNestedRS() throws SQLException {

    Connection con =null;
    try {
        // GET A CONNECTION
        con = ConexionDesdeArchivo.obtenerConexion("examen-dest");
        String sql1 = "select * from reportes_clasificacion";

        Statement st1 = con.createStatement(
                ResultSet.TYPE_SCROLL_INSENSITIVE,
                ResultSet.CONCUR_READ_ONLY, 
                ResultSet.HOLD_CURSORS_OVER_COMMIT);
        ResultSet rs1 = null;

        try {
            // EXECUTE THE FIRST QRY
            rs1 = st1.executeQuery(sql1);

            while (rs1.next()) {
                // THIS LINE WILL BE PRINTED JUST ONCE ON
                                    // SOME DRIVERS UNLESS YOU CREATE THE STATEMENT 
                // WITH 3 PARAMETERS USING 
                                    // ResultSet.HOLD_CURSORS_OVER_COMMIT
                System.out.println("ST1 Row #: " + rs1.getRow());

                String sql2 = "select * from reportes";
                Statement st2 = con.createStatement(
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_READ_ONLY);

                // EXECUTE THE SECOND QRY.  THIS CLOSES THE FIRST 
                // ResultSet ON SOME DRIVERS WITHOUT USING 
                                    // ResultSet.HOLD_CURSORS_OVER_COMMIT

                st2.executeQuery(sql2);

                st2.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            rs1.close();
            st1.close();
        }

    } catch (SQLException e) {

    } finally {
        con.close();

    }

}

b)コードにバグがある可能性があります。 Statementオブジェクトを再利用することはできません。同じステートメントオブジェクトに対してクエリを再実行すると、そのステートメントに関連付けられている開いている結果セットはすべて閉じられます。ステートメントを閉じていないことを確認してください。

20
Sugar

また、各ステートメントから開くことができる結果セットは1つのみです。したがって、2つの結果セットを同時に繰り返し処理する場合は、それらが異なるステートメントで実行されることを確認してください。 1つのステートメントで2番目の結果セットを開くと、最初のステートメントが暗黙的に閉じられます。 http://Java.Sun.com/javase/6/docs/api/Java/sql/Statement.html

10
job

例外は、結果が閉じていることを示しています。コードを調べて、ResultSet.close()呼び出しを発行するすべての場所を探す必要があります。 Statement.close()およびConnection.close()も探してください。確かに、それらの1つはrs.next()が呼び出される前に呼び出されます。

7
Itay Maman

ConnectionまたはStatementを作成したResultSetを閉じた可能性があります。これにより、ResultSetも閉じられます。

6
Nathaniel Flath

適切なjdbc呼び出しは次のようになります。

_try { 
    Connection conn;
    Statement stmt;
    ResultSet rs; 

    try {
        conn = DriverManager.getConnection(myUrl,"",""); 
        stmt = conn.createStatement(); 
        rs = stmt.executeQuery(myQuery); 

        while ( rs.next() ) { 
            // process results
        } 

    } catch (SqlException e) { 
        System.err.println("Got an exception! "); 
        System.err.println(e.getMessage()); 
    } finally {
        // you should release your resources here
        if (rs != null) { 
            rs.close();
        }

        if (stmt != null) {
            stmt.close();
        }

        if (conn != null) {
            conn.close();
        }
    }
} catch (SqlException e) {
    System.err.println("Got an exception! "); 
    System.err.println(e.getMessage()); 
}
_

結果セットから結果を取得した後にのみ、接続(またはステートメント)を閉じることができます。最も安全な方法は、finallyブロックで行うことです。ただし、close()SqlExceptionもスローする可能性があるため、他の_try-catch_ブロックもスローされます。

4
Slartibartfast

同じエラーが発生しましたが、データベースを実行および更新するために同じステートメントインターフェイスオブジェクトを使用していた場合にのみすべてが正しかったです。クエリを更新および実行するためにステートメントインターフェイスの異なるオブジェクトを使用して分離した後、このエラーを解決しました。つまり、これを取り除くには、クエリの更新と実行の両方に同じステートメントオブジェクトを使用しないでください。

2

このコードがstaticとして実行されているメソッドを宣言したかどうかを確認します。 staticである場合、他のスレッドがResultSetをリセットしている可能性があります。

2
Praveen

rs.nextを実行する前に、すべてのステートメントと結果セットを閉じていることを確認してください。 Finalyはこれを保証します

public boolean flowExists( Integer idStatusPrevious, Integer idStatus, Connection connection ) {
    LogUtil.logRequestMethod();

    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        ps = connection.prepareStatement( Constants.SCRIPT_SELECT_FIND_FLOW_STATUS_BY_STATUS );
        ps.setInt( 1, idStatusPrevious );
        ps.setInt( 2, idStatus );

        rs = ps.executeQuery();

        Long count = 0L;

        if ( rs != null ) {
            while ( rs.next() ) {
                count = rs.getLong( 1 );
                break;
            }
        }

        LogUtil.logSuccessMethod();

        return count > 0L;
    } catch ( Exception e ) {
        String errorMsg = String
            .format( Constants.ERROR_FINALIZED_METHOD, ( e.getMessage() != null ? e.getMessage() : "" ) );
        LogUtil.logError( errorMsg, e );

        throw new FatalException( errorMsg );
    } finally {
        rs.close();
        ps.close();
    }
0

ResultSetClosedExceptionは、2つの理由でスローされる可能性があります。

1.)他のすべての接続を閉じずに、データベースへの別の接続を開きました。

2.)ResultSetが値を返さない場合があります。したがって、ResultSet Javaからデータにアクセスしようとすると、ResultSetClosedExceptionがスローされます。

0