我有点困惑了。我正在阅读以下内容: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
表单还是两者兼而有之?
网站不断间歇性宕机,但服务器一直说这是数据库连接问题。我怀疑它没有被关闭,但我不知道要关闭哪个(如果有的话)。
使用完
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
类正是这样做的,因此无需编写自己的类。
使用后关闭数据库/资源对象总是更好。 最好关闭
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在使用后自动关闭这些资源。
实际上,最好使用 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 连接或来自池的连接的调用。
只需关闭
Statement
和 Connection
就足够了。无需显式关闭 ResultSet
对象。
Java 文档介绍了
java.sql.ResultSet
:
当 Statement 对象被关闭、重新执行或用于从多个结果序列中检索下一个结果时,ResultSet 对象会被生成它的 Statement 对象自动关闭。
感谢 BalusC 的评论:“我不会依赖于此。某些 JDBC 驱动程序在此方面失败。”
是的。您需要关闭结果集、语句和连接。如果连接来自池,关闭它实际上会将其发送回池以供重用。
您通常必须在
finally{}
块中执行此操作,这样如果引发异常,您仍然有机会关闭它。
许多框架都会为您处理这个资源分配/释放问题。例如Spring 的 JdbcTemplate。 Apache DbUtils 有方法在关闭结果集/语句/连接后查看是否为 null(并在关闭时捕获异常),这也可能有帮助。
是的,您需要关闭
Connection
。否则,数据库客户端通常会保持套接字连接和其他资源打开。
更好的是使用 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;
}
}
}
从 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