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

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

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

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

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

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对象,所有与该语句关联的打开结果集都将被关闭。 确保您没有结束声明。

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

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

您可能已关闭构成ResultSetConnectionStatement ,这也会导致ResultSet关闭。

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

检查是否已将此代码执行的方法声明为static 。 如果它是static则可能有一些其他线程重置ResultSet

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

确保在运行rs.next之前关闭了所有的语句和结果集。 最终保证这一点

 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(); }