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

时间:2014-08-25 20:27:32

标签: java sql jdbc

关闭与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;
}

4 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:10)

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

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

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

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

public static List<T> sqlquery (String query, RowMapper<T> 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<T> list = new ArrayList<T>();
    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;
}

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

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

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

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

答案 2 :(得分:2)

RowSetFactory factory = RowSetProvider.newFactory();
CachedRowSet rowset = factory.createCachedRowSet();
rowset.populate(ResultSet data)

/ *现在您可以关闭连接并准备语句* /

答案 3 :(得分:1)

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

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