关闭与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;
}
答案 0 :(得分:10)
这是JDBC的工作方式。在您的代码中,您关闭了ResultSet
和Connection
,之后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,这样您就可以获得所需的数据而无需保持连接活动。