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

sol*_*oth 28 java sql exception

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

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

Apo*_*isp 50

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

  • 对于所有驱动程序和RDBMS,情况并非如此. (6认同)

Sug*_*gar 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();

    }

}
Run Code Online (Sandbox Code Playgroud)

b)您的代码中可能存在错误.请记住,一旦在同一语句对象上重新执行查询,就无法重用Statement对象,所有与该语句关联的打开结果集都将被关闭.确保您没有结束声明.


job*_*job 10

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


Ita*_*man 7

该异常表明您的结果已关闭.您应检查代码并查找发出ResultSet.close()呼叫的所有位置.也寻找Statement.close()Connection.close().可以肯定的是,其中一个在调用之前rs.next()被调用.


Nat*_*ath 6

你可能已经关闭,要么Connection或者Statement是做出的ResultSet,这将导致ResultSet被关闭为好.


Sla*_*ast 5

正确的 JDBC 调用应该类似于现代 Java (Java 7+):

try (
    Connection  conn = DriverManager.getConnection(myUrl,"",""); 
    Statement stmt = conn.createStatement(); 
    ResultSet  rs = stmt.executeQuery(myQuery); 
) {
    while ( rs.next() ) { 
        // process results
    } 
} catch (SqlException e) {
    System.err.println("Got an exception! "); 
    System.err.println(e.getMessage()); 
}
Run Code Online (Sandbox Code Playgroud)

在try-with-resources语法出现之前,在 Java 6 及更早版本中:

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()); 
}
Run Code Online (Sandbox Code Playgroud)

只有从结果集中获得结果后才能关闭连接(或语句)。最安全的方法是分块进行finally。然而close()也可能会痛苦SqlException,因此另一个try-catch块。