Java 中关闭数据库连接

问题描述 投票:0回答:8

我有点困惑了。我正在阅读以下内容:Java 数据库连接

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    // It's important to close the statement when you are done with it
    stmt.close();
}

不需要关闭

conn
连接吗? 如果 conn.close() 没有发生,到底发生了什么?

我正在维护一个私人 Web 应用程序,当前不会关闭任一表单,但重要的表单真的是

stmt
表单、
conn
表单还是两者兼而有之?

网站不断间歇性宕机,但服务器一直说这是数据库连接问题。我怀疑它没有被关闭,但我不知道要关闭哪个(如果有的话)。

java database-connection
8个回答
225
投票

使用完

Connection
后,您需要通过调用其
close()
方法显式关闭它,以释放连接可能保留的任何其他数据库资源(游标、句柄等)。

实际上,Java 中的安全模式是在使用完

ResultSet
Statement
Connection
(按顺序)后,将它们关闭在
finally
块中。像这样的东西:

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 */ }
}

但是,这仍然非常冗长,因此您通常最终会使用辅助类来关闭空安全辅助方法中的对象,并且

finally
块会变成这样:

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

实际上,Apache Commons DbUtils 有一个

DbUtils
类正是这样做的,因此无需编写自己的类。


73
投票

使用后关闭数据库/资源对象总是更好。 最好关闭

finally
块中的连接、结果集和语句对象。

在 Java 7 之前,所有这些资源都需要使用

finally
块关闭。如果您使用的是Java 7,那么要关闭资源,您可以执行以下操作。

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

    // Statements
}
catch(....){}

现在,

con
stmt
rs
对象成为try块的一部分,Java在使用后自动关闭这些资源。


15
投票

实际上,最好使用 try-with-resources 块,当您退出 try 块时,Java 会为您关闭所有连接。

您应该对任何实现 AutoClosable 的对象执行此操作。

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

对 getDatabaseConnection 的调用刚刚完成。将其替换为为您获取 JDBC SQL 连接或来自池的连接的调用。


14
投票

只需关闭

Statement
Connection
就足够了。无需显式关闭
ResultSet
对象。

Java 文档介绍了

java.sql.ResultSet
:

当 Statement 对象被关闭、重新执行或用于从多个结果序列中检索下一个结果时,ResultSet 对象会被生成它的 Statement 对象自动关闭。


感谢 BalusC 的评论“我不会依赖于此。某些 JDBC 驱动程序在此方面失败。”


11
投票

是的。您需要关闭结果集、语句和连接。如果连接来自池,关闭它实际上会将其发送回池以供重用。

您通常必须在

finally{}
块中执行此操作,这样如果引发异常,您仍然有机会关闭它。

许多框架都会为您处理这个资源分配/释放问题。例如Spring 的 JdbcTemplateApache DbUtils 有方法在关闭结果集/语句/连接后查看是否为 null(并在关闭时捕获异常),这也可能有帮助。


7
投票

是的,您需要关闭

Connection
。否则,数据库客户端通常会保持套接字连接和其他资源打开。


2
投票

更好的是使用 Try With Resources 块

try (Connection connection = DriverManager.getConnection(connectionStr, username, password)) {
    try (PreparedStatement statement = connection.prepareStatement(query)) {
        statement.setFetchSize(100);
        try (ResultSet resultSet = statement.executeQuery()) {
            List<String> results = new ArrayList<>();
            while (resultSet.next()) {
                String value = resultSet.getString(1);
                results.add(value);
                System.out.println(value);
            }
            return results;
        }
    }
}

0
投票

从 Java 9 开始,可以使用已经声明的变量:

FileOutputStream fos = new FileOutputStream("filename");
XMLEncoder xEnc = new XMLEncoder(fos);
try (fos; xEnc) {
    xEnc.writeObject(object);
} catch (IOException ex) {
    Logger.getLogger(Serializer.class.getName()).log(Level.SEVERE, null, ex);
}

您甚至可以在这里阅读更多内容 https://bugs.openjdk.org/browse/JDK-7196163

© www.soinside.com 2019 - 2024. All rights reserved.