收集JDBC对象的引用并在循环中关闭它们是否安全?

时间:2011-12-14 21:33:40

标签: java jdbc resources

所以我试图重构一些在循环中创建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或其他地方,请告诉我。

4 个答案:

答案 0 :(得分:2)

这是恕我直言,至少有三个原因:

  1. 不再使用资源时,不会立即清除资源。 ResultSet是一种昂贵的资源,我甚至不确定您是否可以在一个连接上打开多个结果集(更新:您可以,请参阅注释)。

  2. 在这种方法中,您将同时打开多个资源,这可能会导致数据库资源和峰值的过度和不必要的使用。如果迭代次数很多,则特别危险。

  3. 前一点的一个特例是内存 - 如果StatementResultSet拥有大量内存,那么对多个此类对象保持不必要的引用会导致内存使用过多。

  4. 据说,考虑使用已构建且安全的实用程序类,如JdbcTemplate。我知道它来自Spring框架,但您可以在容器外部使用它(只需传递DataSource的实例),而不必担心再次关闭JDBC资源。

答案 1 :(得分:1)

不一定是泄密,但我可以看到问题。

我使用Oracle JDBC(特别是)的经验告诉我,处理JDBC资源时最好的办法就是按照打开它们的相反顺序关闭它们。每次。尽快。

收集它们以供以后清理,并以不同的顺序释放它们可能会导致问题。我无法看到一个具体的例子,但甲骨文似乎是最让我困扰的一个例子。

之前,在Statement之前释放ResultSet是好的,但它可能还不够。

答案 2 :(得分:1)

这确实很糟糕,因为它可能会迫使数据库保留您不再使用的资源。我已经看到无法关闭Statement或ResultSet对象(无法记住哪些;可能两者)导致Oracle中的游标泄漏错误的情况。

答案 3 :(得分:0)

您应该在try中完成所有工作,并且只关闭finally中的连接。这是标准模式。