【问题标题】:Problem with not closing db connection while debugging?调试时不关闭数据库连接的问题?
【发布时间】:2011-01-08 11:20:13
【问题描述】:

我有一个 Java 应用程序,它在开始时打开与数据库的连接,并在结束时关闭它。但是,程序并不总是完成,因为抛出异常或者我正在调试它并在中途停止它。

这会导致打开的连接堆积并减慢数据库,还是会自动清理?

【问题讨论】:

    标签: java jdbc


    【解决方案1】:

    数据库连接由数据库拥有和管理,该类只允许您访问该数据库资源。如果你不关闭连接,那么 Java 类可能会被垃圾收集,但数据库可能无法判断连接不再使用,这可能会导致数据库资源被浪费(直到数据库端超时) 甚至泄漏。

    因此,当您使用完 Connection 后,您应该确定通过调用其 close() 方法显式关闭它。这将允许垃圾收集器尽早回收内存,并且更重要,它会释放连接可能占用的任何其他数据库资源(游标、句柄等)。

    在 Java 中执行此操作的传统方法是在完成 finally 块时关闭 ResultSetStatementConnection(按此顺序),安全模式如下所示那:

    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    
    try {
        // Do stuff
        ...
    
    } catch (SQLException ex) {
        // Exception handling stuff
        ...
    } finally {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) { /* ignored */}
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) { /* ignored */}
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) { /* ignored */}
        }
    }
    

    finally 块可以稍微改进为(以避免空检查):

    } finally {
        try { rs.close(); } catch (Exception e) { /* ignored */ }
        try { ps.close(); } catch (Exception e) { /* ignored */ }
        try { conn.close(); } catch (Exception e) { /* ignored */ }
    }
    

    但是,这仍然非常冗长,因此您通常最终会使用辅助类来关闭 null 安全辅助方法中的对象,而 finally 块会变成这样:

    } finally {
        DbUtil.closeQuietly(rs);
        DbUtil.closeQuietly(ps);
        DbUtil.closeQuietly(conn);
    }
    

    实际上,Apache Commons DbUtils 有一个 DbUtils 类,它正是这样做的,所以不需要自己编写。

    在您的情况下,这将解决异常问题,但不能解决调试问题(并且您将浪费数据库资源,直到数据库端发生超时)。所以 1. 不要使用生产数据库调试你的代码 2. 尝试执行你的调试会话直到结束。

    【讨论】:

    • Sun 的人在决定不使用析构函数时简直是疯了。在 C++ 等析构函数中关闭任何打开的资源要容易得多。现在,看看我们需要为一个小型数据库查询编写的所有垃圾......它应该在 3 行代码中完成:连接到数据库、执行查询、获取结果。
    【解决方案2】:

    这是 Sun(错误...Oracle?)says

    建议程序员在不再需要时明确关闭他们创建的连接和语句。

    使用 Java 编程语言编写代码且不使用任何外部资源的程序员无需担心内存管理。垃圾收集器会在不再使用对象时自动删除它们并释放它们正在使用的内存。当内存不足时,它会回收丢弃的对象,使它们当前占用的内存可以快速重用。

    但是,如果应用程序使用外部资源,就像它使用 JDBC API 访问 DBMS 时那样,垃圾收集器无法知道这些资源的状态。它仍然会回收丢弃的对象,但如果 Java 堆中有大量空闲内存,它可能会不频繁地进行垃圾收集,即使(少量)Java 垃圾占用了大量昂贵的数据库资源。因此,建议程序员在不再需要时立即显式关闭所有连接(使用 Connection.close 方法)和语句(使用 Statement.close 方法),从而尽早释放 DBMS 资源。这尤其适用于旨在与不同 DBMS 一起工作的应用程序,因为一个 DBMS 之间存在差异。

    我会将数据库访问放在 try 块中,并确保在 finally 块中关闭所有语句和连接。

    【讨论】:

      【解决方案3】:

      您的数据库服务器将有一个超时设置。它将关闭连接并回滚任何未提交的事务。几十年来,任何具有生产能力的数据库产品都在发生这种情况。

      如果你想正确使用 try { ..your code..} finally { ..close connections..}

      【讨论】:

      • 另外,大多数 DB 协议 ping 另一端以查看它是否还活着。
      【解决方案4】:

      没有。

      如果您的程序继续进行并且您的连接仍然存在,那么 BD 就会拒绝您的判决。

      如果您的连接发生了问题(例如超时),那么 BD 就是关闭了该连接的人,并且它没有消耗资源。

      如果您释放了连接,并且调用了垃圾收集器(可能需要一段时间),则连接将在被释放之前自行关闭。

      如果您的程序在没有关闭连接的情况下终止,那么所有(操作系统)进程将释放其本机资源,并在它们之间释放连接到 BD 的本机资源(可能是网络套接字)。然后 BD 将收到中止/关闭的连接并释放您的连接。

      唯一可能发生的情况是,只有一次执行会多次连接到 BD 并做一些非常糟糕的事情来保持它们打开,从而占用所有可用的连接。但我认为这不是你的情况。

      编辑:通常,BD 是不良客户行为-证明

      【讨论】:

        猜你喜欢
        • 2022-06-10
        • 1970-01-01
        • 2022-01-02
        • 2011-06-25
        • 1970-01-01
        • 2011-10-19
        • 2013-10-16
        • 1970-01-01
        相关资源
        最近更新 更多