java jdbc 处理连接池连接复用的核心做法是拦截 connection 对象的创建与关闭请求,将物理连接的归还逻辑替换为放入池中并标记为可用。开发者只需在代码中配置一个支持复用机制的连接池实现(如 hikaricp、druid),并在获取连接时调用 getconnection(),释放时调用 close(),底层便会自动完成复用,无需手动管理物理连接的生命周期。

连接池如何拦截 close() 方法实现复用
连接池通过动态代理或继承机制接管了 Connection 对象的行为。当业务代码调用 close() 时,实际执行的是池化逻辑而非断开数据库连接。这种设计使得物理连接可以在多个业务事务之间流转,从而减少频繁建立和销毁 TCP 连接的开销。

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class PoolExample {
public static void main(String[] args) throws Exception {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(5);
try (HikariDataSource ds = new HikariDataSource(config)) {
// 获取连接,池内若无空闲连接则新建
java.sql.Connection conn = ds.getConnection();
System.out.println("Is proxy: " + conn.toString().contains("Proxy"));
// 模拟使用
conn.createStatement().executeQuery("SELECT 1");
// 调用 close() 实际是将连接归还给池,而非断开
conn.close();
}
}
}
连接池中的状态机与空闲检测机制
连接池内部维护了一个状态机来追踪每个物理连接的生命周期。连接在创建后进入“活跃”状态,被线程占用;归还后进入“空闲”状态,等待下一次分配。为了防止僵尸连接,池化组件会定期运行心跳检测或超时清理任务,剔除失效的物理连接并补充新连接。
立即学习“Java免费学习笔记(深入)”;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.util.concurrent.TimeUnit;
public class IdleTest {
public static void main(String[] args) throws Exception {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(2);
// 设置空闲超时时间,超过此时间的连接将被回收
config.setIdleTimeout(TimeUnit.MINUTES.toMillis(10));
config.setMaxLifetime(TimeUnit.MINUTES.toMillis(30));
HikariDataSource ds = new HikariDataSource(config);
// 获取第一个连接
java.sql.Connection c1 = ds.getConnection();
// 获取第二个连接
java.sql.Connection c2 = ds.getConnection();
// 此时池已满,若再获取将阻塞或抛出异常
// 归还第一个连接,它变为空闲
c1.close();
// 再次获取,可能复用刚才归还的 c1 物理连接
java.sql.Connection c3 = ds.getConnection();
c2.close();
c3.close();
ds.close();
}
}
最大连接数满时的阻塞行为如何处理
当所有物理连接都被占用且达到 maximumPoolSize 上限时,新的 getConnection() 调用不会立即失败,而是根据配置进行阻塞等待。开发者可以通过调整 connectionTimeout 参数来控制等待时长,超时未获取到连接则会抛出 SQLException。这种背压机制防止了系统因连接耗尽而崩溃,但要求业务代码必须妥善处理超时异常。


















