据说在使用后关闭所有JDBC资源是一个好习惯。但是,如果我有以下代码,是否有必要关闭Resultset和Statement?
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = // Retrieve connection
stmt = conn.prepareStatement(// Some SQL);
rs = stmt.executeQuery();
} catch(Exception e) {
// Error Handling
} finally {
try { if (rs != null) rs.close(); } catch (Exception e) {};
try { if (stmt != null) stmt.close(); } catch (Exception e) {};
try { if (conn != null) conn.close(); } catch (Exception e) {};
}
问题是连接的关闭是否完成了工作,或者是否正在使用某些资源。
答案 0 :(得分:180)
你所做的是完美和非常好的练习。
我说它的良好做法的原因......例如,如果由于某种原因你使用“原始”类型的数据库池并且你调用connection.close()
,那么连接将被返回到池中并且ResultSet
/ Statement
永远不会被关闭,然后您会遇到许多不同的新问题!
所以你不能总是依靠connection.close()
来清理。
我希望这会有所帮助:)
答案 1 :(得分:109)
由于try-with-resources statement,Java 1.7让我们的生活更轻松。
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
try (ResultSet resultSet = statement.executeQuery("some query")) {
// Do stuff with the result set.
}
try (ResultSet resultSet = statement.executeQuery("some query")) {
// Do more stuff with the second result set.
}
}
这种语法非常简洁和优雅。即使无法创建connection
,statement
也会被关闭。
答案 2 :(得分:65)
来自javadocs:
当
Statement
对象关闭时,它 当前ResultSet
对象,如果有的话 存在,也是关闭的。
但是,关闭基础Statement
时,javadocs关于ResultSet
和Connection
是否已关闭并不是很明确。他们只是声明关闭连接:
发布此
Connection
个对象 数据库和JDBC资源 马上而不是等待 它们会被自动释放。
在我看来,当你完成它们时,总是明确地关闭ResultSets
,Statements
和Connections
,因为close
的实现可能因数据库驱动程序而异。
您可以使用Apache中的DBUtils中的closeQuietly
等方法为自己节省大量的样板代码。
答案 3 :(得分:35)
我现在正在使用Oracle和Java。在这里我的观点是:
您应该明确关闭ResultSet
和Statement
,因为Oracle之前在关闭连接后保持游标保持打开存在问题。如果不关闭ResultSet
(光标),则会抛出超出最大打开游标数之类的错误。
我认为您使用的其他数据库可能遇到同样的问题。
这是教程Close ResultSet when finished:
完成后关闭ResultSet
完成后立即关闭
ResultSet
个对象 甚至与ResultSet
对象一起工作 虽然Statement
对象关闭了ResultSet
隐含的对象 关闭,明确关闭ResultSet
给垃圾收集器机会 尽早回忆记忆 因为ResultSet
对象可能占用 大量内存取决于查询。
ResultSet.close();
答案 4 :(得分:6)
如果您想要更紧凑的代码,我建议使用Apache Commons DbUtils。在这种情况下:
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = // Retrieve connection
stmt = conn.prepareStatement(// Some SQL);
rs = stmt.executeQuery();
} catch(Exception e) {
// Error Handling
} finally {
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(stmt);
DbUtils.closeQuietly(conn);
}
答案 5 :(得分:3)
关闭与JDBC相关的资源的正确且安全的方法(取自How to Close JDBC Resources Properly – Every Time):
Connection connection = dataSource.getConnection();
try {
Statement statement = connection.createStatement();
try {
ResultSet resultSet = statement.executeQuery("some query");
try {
// Do stuff with the result set.
} finally {
resultSet.close();
}
} finally {
statement.close();
}
} finally {
connection.close();
}
答案 6 :(得分:2)
Connection
是否可合并无关紧要。即使是可池化的连接也必须在返回池之前进行清理。
“清除”通常意味着关闭结果集并回滚任何未决的事务,但不关闭连接,否则池将失去其意义。
答案 7 :(得分:0)
不,你不需要关闭任何东西,但连接。根据JDBC规范,关闭任何更高的对象将自动关闭较低的对象。关闭Connection
将关闭该连接创建的所有Statement
。关闭任何Statement
将关闭由ResultSet
创建的所有Statement
。 Connection
是否可以使用并不重要。即使是poolable连接也必须在返回游泳池之前进行清洁。
当然,您可能在Connection
上创建了很多嵌套循环来创建大量语句,然后关闭它们是合适的。我几乎从未关闭ResultSet
但是,当关闭Statement
或Connection
关闭它们时似乎过多。
答案 8 :(得分:0)
一些便利功能:
public static void silentCloseResultSets(Statement st) {
try {
while (!(!st.getMoreResults() && (st.getUpdateCount() == -1))) {}
} catch (SQLException ignore) {}
}
public static void silentCloseResultSets(Statement ...statements) {
for (Statement st: statements) silentCloseResultSets(st);
}
答案 9 :(得分:0)
我创建了以下方法来创建可重复使用的“一线”:
public void oneMethodToCloseThemAll(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
if (!resultSet.isClosed()) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
if (!statement.isClosed()) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
if (!connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
我在继承给我所有发送DB查询的类的父类中使用此代码。即使我没有resultSet我也可以在所有查询上使用Oneliner。该方法负责按正确的顺序关闭ResultSet,Statement和Connection。这就是我的finally块的样子。
finally {
oneMethodToCloseThemAll(resultSet, preStatement, sqlConnection);
}
答案 10 :(得分:-1)
使用Java 6表单我认为最好在关闭之前检查它是否关闭(例如,如果某个连接池在其他线程中逐出连接) - 例如某些网络问题 - 语句和结果集状态可以关闭。 (它经常发生,但我在Oracle和DBCP中遇到了这个问题)。我的模式(在较旧的Java语法中)是:
try {
...
return resp;
} finally {
if (rs != null && !rs.isClosed()) {
try {
rs.close();
} catch (Exception e2) {
log.warn("Cannot close resultset: " + e2.getMessage());
}
}
if (stmt != null && !stmt.isClosed()) {
try {
stmt.close();
} catch (Exception e2) {
log.warn("Cannot close statement " + e2.getMessage());
}
}
if (con != null && !conn.isClosed()) {
try {
con.close();
} catch (Exception e2) {
log.warn("Cannot close connection: " + e2.getMessage());
}
}
理论上它不是100%完美,因为在检查关闭状态和关闭本身之间,状态的变化有一点空间。在最坏的情况下,你会得到一个警告。 - 但它比长期查询中状态更改的可能性要小。我们在生产中使用这种模式,带有“avarage”负载(150同时用户),我们没有遇到任何问题 - 所以永远不要看到这个警告信息。
答案 11 :(得分:-1)
据我所记得,在当前的JDBC中,结果集和语句实现了AutoCloseable接口。这意味着它们一旦被破坏或超出范围就会自动关闭。