Java – 连接关闭后无法使用ResultSet

关闭与MySQL的连接时遇到问题。

我收到了错误:

java.sql.SQLException:ResultSet关闭后不允许操作

我的代码:

public static ResultSet sqlquery (String query) { ResultSet rs=null; Connection connection=null; Statement st=null; try{ Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("databaseadress","username","password"); st = connection.createStatement(); rs = st.executeQuery(query); }catch(SQLException e){System.out.println("SQL error: " + e);} catch(Exception e){System.out.println("Error: " + e);} finally { try{ if(rs != null) rs.close(); if(st!= null) st.close(); if(connection != null) connection.close(); }catch(SQLException e){System.out.println("SQL error : " + e);} } return rs; } 

这是JDBC的工作方式。 在您的代码中,您关闭了ResultSetConnection ,之后ResultSet不再可用。 如果您希望它可用,您必须将它(和Connection )保持打开状态。

但是,如果返回ResultSet ,则应重构代码,以便调用方法提供Connection

JDBC不会在ResultSet中带回查询的所有结果,因为可能有太多的查询结果都是急切地获取它们。 相反,它会为您提供可用于检索结果的内容,但在连接关闭时会消失。 因此,在关闭数据库连接后从方法中将其传回时,没有其他任何东西可以使用它。

您可以做的是让此方法使用resultSet填充对象或对象集合,并将该填充的对象传回。

如果您更改代码以传入rowMapper(它接受一个resultSet并传回一个填充了结果集中当前行的对象),并使用它来填充您传回的容器对象,那么您将拥有可以重复使用你所编写的内容,但实际上是可行的,因为它不依赖于在调用完成后保持连接打开。

这是你的示例代码重写使用rowmapper,摆脱一些不必要的exception捕获,并修复一个错误,以防止连接在某些情况下被关闭:

 public static List sqlquery (String query, RowMapper rowMapper) throws SQLException { Connection connection=null; Statement st=null; ResultSet rs=null; // don't need Class.forName anymore with type4 driver connection = DriverManager.getConnection("databaseadress","username","password"); st = connection.createStatement(); rs = st.executeQuery(query); List list = new ArrayList(); while (rs.next()) { list.add(rowMapper.mapRow(rs)); } // don't let exception thrown on close of // statement or resultset prevent the // connection from getting closed if(rs != null) try {rs.close()} catch (SQLException e){log.info(e);} if(st!= null) try {st.close()} catch (SQLException e){log.info(e);} if(connection != null) try {connection.close()} catch (SQLException e){log.info(e);} return list; } 

如果您没有捕获单独关闭时抛出的每个exception,如上所示,如果语句或resultSet在关闭时抛出exception,则可能无法关闭连接。

这类似于spring-jdbc所做的,它将RowMapper定义为:

 public interface RowMapper { T mapRow(ResultSet, int rowNum) throws SQLException; } 

下一步是参数化您的查询,这样您就不必在引号中包围参数值或担心sql注入。 有关spring-jdbc如何处理此问题的示例,请参阅此答案 。 这里的长期答案是,最好采用spring-jdbc或类似的东西,而不是重新发明它。

关闭连接后,您将无法再使用任何资源(语句,预准备语句,结果集),所有这些资源都将自动关闭。 因此,您需要在资源打开时执行所有处理。

尝试填充并返回DTO,这样您就可以获得所需的数据,而无需保持连接活动。