必须将Connection、Statement、ResultSet统一声明在try括号内,JVM按逆序自动调用close();声明顺序应为Connection→Statement→ResultSet,确保依赖关系正确且异常时资源不泄漏。

Java 数据库连接用 try-with-resources 避免内存泄漏,核心就一条:把 Connection、Statement、ResultSet 这些实现了 AutoCloseable 的对象,全部声明在 try 括号里,JVM 会自动按逆序调用 close(),哪怕执行中抛异常也不会漏关。
必须声明在 try 括号里的三类资源
数据库操作中,以下三类对象都实现了 AutoCloseable,必须统一纳入 try-with-resources 管理:
-
java.sql.Connection:数据库连接本身,占用系统句柄和连接池资源 -
java.sql.Statement(或PreparedStatement、CallableStatement):执行 SQL 的载体 -
java.sql.ResultSet:查询结果集,底层常持有网络流或缓存数据
正确写法:多资源嵌套声明,逆序自动关闭
注意声明顺序要符合依赖关系——比如 ResultSet 依赖 Statement,Statement 又依赖 Connection,所以应按“最外层→最内层”顺序声明,JVM 才会按“最内层→最外层”安全关闭:
✅ 正确示例(推荐):
立即学习“Java免费学习笔记(深入)”;
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
ResultSet rs = ps.executeQuery()) {
<pre class="brush:php;toolbar:false;">ps.setLong(1, userId);
while (rs.next()) {
System.out.println(rs.getString("name"));
}
// 执行完自动关闭:rs → ps → conn} catch (SQLException e) { // 异常处理,无需关心 close }
这样写,即使 executeQuery() 抛出异常,ps 和 conn 仍会被依次关闭;即使循环中 rs.next() 出错,前面声明的资源也一个不落。
常见错误写法及后果
这些写法看似能跑通,但极易引发连接泄漏或句柄耗尽:
- 只对
ResultSet用 try-with-resources,而Connection外部手动管理 → 连接长期不归还连接池 - 在 try 块内对资源变量重新赋值(如
ps = conn.prepareStatement(...))→ JVM 关闭的是旧对象,新对象未被管理 - 把
Connection放在 try 外部,仅用 finally 调用close()→ 回退到传统模式,异常时可能跳过关闭 - 使用未实现
AutoCloseable的自定义封装类(如某些老版本 JDBC 工具类)→ 编译报错或关闭失效
配合连接池使用的注意事项
用 HikariCP、Druid 等主流连接池时,close() 实际是归还连接而非真正销毁。但若没走 try-with-resources:
- 连接未归还 → 连接池连接数持续增长,最终
getConnection()超时阻塞 - 连接池内部统计失真,无法准确触发回收或告警
- 某些池(如 HikariCP)会记录“leak detection”,长时间未 close 会打印警告日志
所以,只要连接是从池中获取的,就一定要用 try-with-resources 封装整个链路,这是防止生产环境连接耗尽的最基本防线。


















