用Java关闭数据库连接


121

我有些困惑,我从http://en.wikipedia.org/wiki/Java_Database_Connectivity阅读以下内容

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还是两者兼而有之?

该站点间歇性地关闭,但是服务器一直在说这是数据库连接问题,我怀疑它没有关闭,但是我不知道该关闭哪一个。


最好自行关闭连接,而不依赖其他驱动程序和模板来处理关闭。关闭连接失败将导致套接字和资源永远打开,直到发生崩溃(没有更多资源的情况)或重新启动。
阿伦·乔什拉

Answers:


196

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

实际上,Java中的安全模式是在完成对ResultSet,,StatementConnection(按顺序)关闭后的代码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 */ }
}

但是,这仍然是非常冗长的,因此您通常最终使用helper类在null安全的helper方法中关闭对象,并且该finally块变为类似以下内容:

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

而且,实际上,Apache Commons DbUtils有一个DbUtils正是在这样做的类,因此无需编写自己的类。


3
很棒的帮助,谢谢!我没有抓住也没有想到conn!= null语句。
onaclov2000'2

1
@ onaclov2000是的,rspsconnnull根据其中的代码中断。这就是为什么这被称为“安全”模式。
Pascal Thivent 2010年

12
@Pascal Thivent:实际上,我们不需要关闭所有窗口。《核心Java第二卷-高级功能》一书中写道:如果语句具有打开的结果集,则对象的close方法将Statement自动关闭关联的方法ResultSet。同样,close该方法Connection类关闭所有StatementsConnection
Majid Azimi

12
@Majid:除非是池连接。语句然后会泄漏掉。
BalusC

1
@BalusC:您能解释一下使用connection.close()方法关闭池化连接时会发生什么情况
Krsna Chaitanya 2013年

61

使用后最好关闭数据库/资源​​对象。最好在finally块中关闭连接,结果集和语句对象。

在Java7之前,所有这些资源都需要使用一个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在使用后会自动关闭这些资源。

希望我会有所帮助。


如果我的陈述是隐式的,即ResultSet rs = conn.createStatement().executeQuery(sql);try块内怎么办?
Antares42

1
您将无法在finally {}块中引用它们以进行关闭。如果抛出异常,则永远不会调用ResultSet的close()方法
Dan Dan

如果我不关闭它们会怎样?
Alex78191 '19

如果不关闭它们,则可能发生内存泄漏。
Yadu Krishnan

14

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

Java文档说java.sql.ResultSet

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


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


25
我不会依靠的。某些JDBC驱动程序对此失败。例如,Oracle具有“已超出最大打开游标数”,等等。只需显式关闭所有打开的资源,没有任何借口。
BalusC

1
我宁愿不使用当时不符合规格的驱动程序
Enerccio

2
正如BalusC指出的那样,显式关闭连接而不是硬性依赖特定提供程序是一种很好的防御性编程。
michaelok '18年

11

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

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

许多框架将为您解决此资源分配/分配问题。例如Spring的JdbcTemplateApache DbUtils具有一些方法,可以在关闭结果集/语句/连接后查找是否为空(并在关闭时捕获异常),这也可能会有所帮助。


1
当我插入“最终”日食时,喜欢突出显示它,告诉我这是错误的。应该在捕获块之后执行吗?
onaclov2000 '02

是。试试{}抓住{}最后{}。catch {}是可选的,顺便说一句。就像最后{}一样
Brian Agnew

我将“ close”语句移到了最后,但它们只是在说“ sqlexception”,有什么建议吗?
onaclov2000'2

1
close()引发SQLException。您必须处理。请参阅DbUtils.closeQuietly()以静默方式处理此问题。
Brian Agnew

>如果conn.close()没有发生,那实际上是怎么回事?
Alex78191 '19

8

实际上,最好使用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连接或来自池的连接的调用。


因此,在这种情况下,您不必手动关闭连接?
Colin D

1
正确。您不必显式关闭连接。当到达try代码块的末尾时,它将关闭。

7

是的,您需要关闭连接。否则,数据库客户端通常将保持套接字连接和其他资源打开。


...直到退出 这限制了客户端和服务器端的各种有限资源。如果客户端执行此类操作过多,可能会给客户端本身,数据库服务甚至在客户端或服务器计算机上运行的其他应用程序造成问题。
斯蒂芬·C
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.