【发布时间】:2023-03-19 12:12:01
【问题描述】:
一旦我的代码进入我的while(rs.next()) 循环,它就会产生ResultSet is closed 异常。是什么导致了这个异常,我该如何纠正它?
编辑:我注意到我在我的代码中嵌套了 while(rs.next()) 循环和另一个 (rs2.next()),两个结果集都来自同一个数据库,这是一个问题吗?
【问题讨论】:
一旦我的代码进入我的while(rs.next()) 循环,它就会产生ResultSet is closed 异常。是什么导致了这个异常,我该如何纠正它?
编辑:我注意到我在我的代码中嵌套了 while(rs.next()) 循环和另一个 (rs2.next()),两个结果集都来自同一个数据库,这是一个问题吗?
【问题讨论】:
听起来您在遍历第一条语句的结果集之前在同一连接中执行了另一条语句。如果您嵌套处理来自同一个数据库的两个结果集,那么您做错了。这些集合的组合应该在数据库端完成。
【讨论】:
这可能是由多种原因造成的,包括您使用的驱动程序。
a) 一些驱动程序不允许嵌套语句。根据您的驱动程序是否支持 JDBC 3.0,您应该在创建 Statement 对象时检查第三个参数。例如,我在使用 JayBird 驱动程序到 Firebird 时遇到了同样的问题,但代码在 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 对象,一旦您对同一个语句对象重新执行查询,与该语句关联的所有打开的结果集都将关闭。确保您没有关闭该语句。
【讨论】:
ResultSet.HOLD_CURSORS_OVER_COMMIT 是否正常工作。
此外,您只能从每个语句中打开一个结果集。因此,如果您同时遍历两个结果集,请确保它们在不同的语句上执行。在一个语句上打开第二个结果集将隐式关闭第一个。 http://java.sun.com/javase/6/docs/api/java/sql/Statement.html
【讨论】:
异常表明您的结果已关闭。您应该检查您的代码并查找您发出ResultSet.close() 调用的所有位置。还要寻找Statement.close() 和Connection.close()。当然,其中一个会在调用 rs.next() 之前被调用。
【讨论】:
您可能已经关闭了产生 ResultSet 的 Connection 或 Statement,这将导致 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。
【讨论】:
ResultSetClosedException 被抛出有两个原因。
1.) 您打开了另一个与数据库的连接,但没有关闭所有其他连接。
2.) 您的 ResultSet 可能没有返回任何值。所以当你尝试从 ResultSet 访问数据时,java 会抛出一个ResultSetClosedException。
【讨论】:
确保在运行 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();
}
【讨论】:
在使用 ResultSet 而不是在 @Transactional 方法中时也会发生这种情况。
ScrollableResults results = getScrollableResults("select e from MyEntity e");
while (results.next()) {
...
}
results.close();
如果 MyEntity 与其他实体有热切的关系。第二次调用 results.next() 会引发 ResultSet is closed 异常。
因此,如果您在具有急切关系的实体上使用 ScrollableResults,请确保您的方法以事务方式运行。
【讨论】: