所以我试图重构一些在循环中创建JDBC对象的代码并没有干净地关闭它们。我的第一个想法是创建一个LinkedList
来存储准备好的语句,结果集等,然后在finally
块内的循环中关闭它们。所以,方法就像:
Connection conn = null;
LinkedList<PreparedStatement> statements = new LinkedList<PreparedStatement>();
LinkedList<ResultSet> results = new LinkedList<ResultSet>();
try {
conn = database.getConnection();
for (String i : arr1) {
for (String j : arr2) {
Statement stmt = conn.createStatement();
statements.add(stmt);
ResultSet rs = stmt.executeQuery(...);
results.add(rs);
// ...work...
}
}
}
catch(SQLException ex) {ex.printStackTrace();}
finally {
// close all result sets..
for (ResultSet rs : (ResultSet[])results.toArray()) {
if (rs != null) try { rs.close(); } catch (SQLException ex) {ex.printStackTrace();}
}
for (Statement stmt : (Statement[])statements.toArray()) {
if (stmt != null) try { stmt.close(); } catch (SQLException ex) {ex.printStackTrace();}
}
if (conn != null) try { conn.close(); } catch (SQLException ex) {ex.printStackTrace();}
}
这是一种合理的方法吗?这最终会导致某种泄漏或问题吗?在此先感谢,如果这属于codereview.se或其他地方,请告诉我。
答案 0 :(得分:2)
这是恕我直言,至少有三个原因:
不再使用资源时,不会立即清除资源。 ResultSet
是一种昂贵的资源,我甚至不确定您是否可以在一个连接上打开多个结果集(更新:您可以,请参阅注释)。
在这种方法中,您将同时打开多个资源,这可能会导致数据库资源和峰值的过度和不必要的使用。如果迭代次数很多,则特别危险。
前一点的一个特例是内存 - 如果Statement
或ResultSet
拥有大量内存,那么对多个此类对象保持不必要的引用会导致内存使用过多。
据说,考虑使用已构建且安全的实用程序类,如JdbcTemplate
。我知道它来自Spring框架,但您可以在容器外部使用它(只需传递DataSource
的实例),而不必担心再次关闭JDBC资源。
答案 1 :(得分:1)
不一定是泄密,但我可以看到问题。
我使用Oracle JDBC(特别是)的经验告诉我,处理JDBC资源时最好的办法就是按照打开它们的相反顺序关闭它们。每次。尽快。
收集它们以供以后清理,并以不同的顺序释放它们可能会导致问题。我无法看到一个具体的例子,但甲骨文似乎是最让我困扰的一个例子。
之前,在Statement之前释放ResultSet是好的,但它可能还不够。答案 2 :(得分:1)
这确实很糟糕,因为它可能会迫使数据库保留您不再使用的资源。我已经看到无法关闭Statement或ResultSet对象(无法记住哪些;可能两者)导致Oracle中的游标泄漏错误的情况。
答案 3 :(得分:0)
您应该在try
中完成所有工作,并且只关闭finally
中的连接。这是标准模式。