代码之家  ›  专栏  ›  技术社区  ›  jb.

连接关闭时结果集未关闭?

  •  49
  • jb.  · 技术社区  · 18 年前

    我一直在对我们的一个宠物项目进行代码审查(主要使用FindBugs等工具),FindBugs将以下代码标记为错误(伪代码):

    Connection conn = dataSource.getConnection();
    
    try{
        PreparedStatement stmt = conn.prepareStatement();
        //initialize the statement
        stmt.execute();
        ResultSet rs =  stmt.getResultSet();
        //get data
    }finally{
        conn.close();
    }
    

    错误是此代码可能无法释放资源。我发现ResultSet和Statement没有关闭,所以我最终关闭了它们:

    finally{
        try{
            rs.close()
        }catch(SqlException se){
            //log it
        }
        try{
            stmt.close();
        }catch(SqlException se){
            //log it
        }
        conn.close();
    }
    

    但我在许多项目中遇到了上述模式(来自相当多的公司),没有人关闭ResultSets或Statements。

    当连接关闭时,您是否遇到结果集和语句未关闭的问题?

    我只找到 this 它指的是Oracle在关闭Connections时关闭ResultSets时遇到问题(我们使用Oracle db,因此我进行了更正)。java.sql.api在Connection.close()javadoc中什么也没说。

    8 回复  |  直到 7 年前
        1
  •  52
  •   bluish dmajkic    14 年前

    只关闭连接而不关闭结果集的一个问题是,如果您的连接管理代码正在使用连接池 connection.close() 只会把连接放回池中。此外,某些数据库在服务器上有一个游标资源,除非明确关闭,否则将无法正确释放。

        2
  •  29
  •   neu242    12 年前

    我在Oracle中遇到了未关闭的ResultSets的问题,即使连接已关闭。我犯的错误是

    "ORA-01000: maximum open cursors exceeded"
    

    所以:始终关闭您的结果集!

        3
  •  19
  •   Stefan Schweizer    18 年前

    您应该始终显式关闭所有JDBC资源。正如Aaron和John所说,关闭连接通常只会将其返回到池中,并且并非所有JDBC驱动程序都以完全相同的方式实现。

    下面是一个可以从finally块中使用的实用方法:

    public static void closeEverything(ResultSet rs, Statement stmt,
            Connection con) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
            }
        }
        if (con != null) {
            try {
                con.close();
            } catch (SQLException e) {
            }
        }
    }
    
        4
  •  9
  •   John Gardner    18 年前

    在这种情况下,Oracle将为您提供有关打开游标的错误。

    根据: http://java.sun.com/javase/6/docs/api/java/sql/Statement.html

    看起来重用一条语句会关闭任何打开的结果集,关闭一条语句也会关闭任何结果集,但我没有看到任何关于关闭连接会关闭它创建的任何资源的信息。

    所有这些细节都留给JDBC驱动程序提供者。

    明确关闭所有内容总是最安全的。我们编写了一个util类,它用try{xxx}catch(Throwable{}包装所有内容,这样你就可以直接调用Utils.close(rs)和Utils.colose(stmt)等,而不必担心关闭扫描会抛出异常。

        5
  •  8
  •   Horcrux7    18 年前

    ODBC桥可能会在某些ODBC驱动程序中产生内存泄漏。

    如果你使用一个好的JDBC驱动程序,那么关闭连接应该没有任何问题。但有两个问题:

    • 你知道你有没有一个好司机吗?
    • 您将来会使用其他JDBC驱动程序吗?

    最好的做法是关闭它。

        6
  •  8
  •   Konrad    18 年前

    我在一个大型J2EE web环境中工作。我们有几个数据库可以在一个请求中连接。我们的一些应用程序开始出现逻辑死锁。问题如下:

    1. 用户将请求页面
    2. 服务器连接到DB 1
    3. DB 1上的服务器选择
    4. 服务器“关闭”与DB 1的连接
    5. 服务器连接到DB 2
    6. 死锁!

    这有两个原因,我们遇到了比正常情况高得多的流量,默认情况下,J2EE规范在线程完成执行之前不会实际关闭您的连接。因此,在上述示例中,步骤4从未实际关闭连接,即使它们最终被正确关闭。

    为了解决这个问题,您必须在web.xml中为数据库连接使用资源引用,并且必须将res共享范围设置为不可共享。

    例子:

    <resource-ref>
        <description>My Database</description>
        <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Unshareable</res-sharing-scope>
    </resource-ref>
    
        7
  •  4
  •   JavadocMD    18 年前

    我肯定看到了未关闭的ResultSets的问题,一直关闭它们会有什么坏处,对吧?需要记住这样做的不可靠性是转向为您管理这些细节的框架的最佳原因之一。这在您的开发环境中可能不可行,但我很幸运地使用Spring来管理JPA事务。打开连接、语句、结果集以及在复杂的try/catch/finally块(带有try/catch块)上编写的混乱细节 在最后一块! )再次关闭它们只会消失,让你真正完成一些工作。我强烈建议迁移到这种解决方案。

        8
  •  4
  •   Spencer Kormos    18 年前

    在Java中,语句(不是结果集)与Oracle中的游标相关。最好关闭您打开的资源,因为JVM和系统资源可能会出现意外行为。

    此外,一些JDBC池框架将语句和连接池化,因此不关闭它们可能不会将这些对象标记为池中的空闲对象,从而导致框架中的性能问题。

    一般来说,如果一个对象上有close()或destroy()方法,那么调用它是有原因的,忽略它是有风险的。

    推荐文章