Callable中应仅获取并归还Connection,不可关闭连接池;需用try-with-resources确保连接自动归还,连接池关闭由Spring容器或JVM钩子统一管理。

在 Callable 中妥善关闭数据库连接池资源,关键不是“关闭连接池本身”,而是**避免在 Callable 内部直接持有或误关连接池(如 HikariDataSource),并确保其创建的短期连接(Connection)被正确归还**。连接池是全局、长期存活的资源,应由应用生命周期统一管理;Callable 任务只应获取、使用、归还连接,不负责销毁池。
明确连接池与连接的职责边界
连接池(如 HikariDataSource)是线程安全、可复用的单例对象,设计上就该在整个应用运行期间持续存在。Callable 任务中:
- ❌ 不要调用
dataSource.close()—— 这会彻底销毁池,影响其他所有任务; - ✅ 应仅调用
dataSource.getConnection()获取连接,并在使用后 必须调用connection.close()—— 对连接池而言,close 就是归还连接,不是销毁; - ✅ 连接池本身的关闭应在 Spring 容器销毁、或 JVM 关闭钩子中统一执行(例如通过
DisposableBean或@PreDestroy)。
在 Callable 中安全使用并归还连接
推荐用 try-with-resources 确保连接及其附属资源(Statement、ResultSet)自动归还:
public class DbQueryTask implements Callable<list>> {
private final DataSource dataSource;
<pre class="brush:php;toolbar:false;">public DbQueryTask(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public List<user> call() throws Exception {
List<user> users = new ArrayList();
// connection.close() 在 try 结束时自动触发归还
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM user WHERE status = ?")) {
stmt.setString(1, "ACTIVE");
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
users.add(new User(rs.getString("name")));
}
}
}
return users;
}</user></user>
}
这样写,即使查询中途抛异常,连接也会被自动归还到池中,不会泄漏。
避免常见陷阱
- 不要把 Connection 存为 Callable 成员变量:Connection 非线程安全,且生命周期应严格限定在单次任务内;
-
不要在 finally 块里重复 close 同一个 connection:若已用 try-with-resources,再手动 close 会抛
SQLException: Connection is closed; - 不要在 Callable 外部提前 close 连接池:比如在提交任务前或线程池 shutdown 时误关 dataSource,会导致后续所有任务失败;
-
注意线程池 shutdown 时机:若用
ExecutorService执行 Callable,应先shutdown()等待任务完成,再(在应用关闭阶段)关闭 dataSource,二者完全解耦。
连接池的统一关闭位置(非 Callable 职责)
连接池关闭属于应用退出逻辑,典型做法有:
- Spring 环境下实现
DisposableBean或标注@PreDestroy方法; - Java SE 环境注册 JVM 关闭钩子:
Runtime.getRuntime().addShutdownHook(...); - 微服务框架(如 Spring Boot)通常自动处理,只需确保配置了
spring.datasource.hikari.shutdown-timeout等参数。
Callable 只管用好连接,不碰池;池的生与死,交给容器或主程序统筹。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











