如何在Java中避免ResultSet被关闭的异常?

时间:2009-06-01 16:09:13

标签: java sql exception

只要我的代码进入while(rs.next())循环,它就会生成ResultSet已关闭的异常。导致此异常的原因是什么?如何更正?

编辑:我在代码中注意到我正在将while(rs.next())循环嵌套到另一个(rs2.next()),这两个结果集来自同一个数据库,这是一个问题吗?< / p>

10 个答案:

答案 0 :(得分:47)

听起来你在遍历第一个语句的结果集之前在同一个连接中执行了另一个语句。如果您正在嵌套来自同一数据库的两个结果集的处理,那么您做错了。这些集合的组合应该在数据库方面完成。

答案 1 :(得分:20)

这可能是由多种原因造成的,包括您正在使用的驱动程序。

a)某些驱动程序不允许嵌套语句。根据您的驱动程序是否支持JDBC 3.0,您应该在创建Statement对象时检查第三个参数。例如,我对Firebird的JayBird驱动程序有同样的问题,但代码与postgres驱动程序一起工作正常。然后我将第三个参数添加到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对象,所有与该语句关联的打开结果集都将被关闭。确保你没有结束陈述。

答案 2 :(得分:10)

此外,每个语句只能打开一个结果集。因此,如果您同时迭代两个结果集,请确保它们在不同的语句上执行。在一个语句上打开第二个结果集将隐式关闭第一个结果集。 http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

答案 3 :(得分:7)

该异常表明您的结果已关闭。您应检查代码并查找发出ResultSet.close()电话的所有位置。另请查找Statement.close()Connection.close()。当然,在调用rs.next()之前会调用其中一个。

答案 4 :(得分:6)

您可能已关闭提出Connection的{​​{1}}或Statement,这也会导致ResultSet被关闭。

答案 5 :(得分:4)

正确的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阻止。

答案 6 :(得分:2)

检查您是否已将此代码执行的方法声明为static。如果是static,可能会有其他一些主题重置ResultSet

答案 7 :(得分:1)

我得到了同样的错误一切都正确我只是使用相同的语句接口对象来执行和更新数据库。 分离后,即使用语句接口的不同对象进行更新和执行查询,我解决了这个错误。即,摆脱这一点,不要使用相同的语句对象来更新和执行查询。

答案 8 :(得分:0)

确保在运行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();
    }

答案 9 :(得分:0)

可以抛出ResultSetClosedException有两个原因。

1。)您已经打开了与数据库的另一个连接,而没有关闭所有其他连接。

2。)您的ResultSet可能不返回任何值。因此,当您尝试从ResultSet访问数据时,java会抛出ResultSetClosedException