本文目录导读:

数据库连接池的核心逻辑是复用数据库连接,避免频繁创建和销毁连接带来的性能开销(TCP三次握手、数据库认证等),手写一个简单的连接池,核心需要实现以下逻辑:
核心接口设计
public interface ConnectionPool {
// 获取连接
Connection getConnection() throws SQLException;
// 归还连接
void releaseConnection(Connection conn);
// 关闭连接池
void shutdown();
}
核心数据结构
public class SimpleConnectionPool implements ConnectionPool {
// 空闲连接池(线程安全)
private LinkedList<Connection> idleConnections = new LinkedList<>();
// 活跃连接数
private AtomicInteger activeCount = new AtomicInteger(0);
// 最大连接数
private int maxSize;
// 最小连接数
private int minSize;
// 连接URL
private String url, username, password;
}
核心逻辑实现
1 初始化连接池
// 预先创建最小数量的连接
public void init() throws SQLException {
for (int i = 0; i < minSize; i++) {
Connection conn = createConnection();
idleConnections.addLast(conn);
}
}
private Connection createConnection() throws SQLException {
Connection conn = DriverManager.getConnection(url, username, password);
// 关键:用代理模式包装连接,拦截close()方法
return new ConnectionProxy(conn, this);
}
2 获取连接(核心方法)
@Override
public Connection getConnection() throws SQLException {
// 从空闲队列获取
Connection conn = getFromPool();
if (conn != null) {
// 验证连接是否有效
if (validateConnection(conn)) {
activeCount.incrementAndGet();
return conn;
} else {
// 无效连接,丢弃并创建新的
closeRealConnection(conn);
conn = createNewConnection();
}
} else {
conn = createNewConnection();
}
return conn;
}
private Connection getFromPool() {
synchronized (idleConnections) {
if (idleConnections.size() > 0) {
return idleConnections.removeFirst();
}
return null;
}
}
private Connection createNewConnection() throws SQLException {
if (activeCount.get() < maxSize) {
Connection conn = createConnection();
activeCount.incrementAndGet();
return conn;
}
// 超过最大连接数,等待或抛出异常
throw new SQLException("连接池已满,最大连接数:" + maxSize);
}
3 归还连接(核心方法)
@Override
public void releaseConnection(Connection conn) {
if (conn == null) return;
activeCount.decrementAndGet();
synchronized (idleConnections) {
// 判断空闲池是否已满
if (idleConnections.size() >= minSize) {
// 空闲过多,关闭连接
closeRealConnection(conn);
} else {
// 放回空闲池
idleConnections.addLast(conn);
}
}
}
4 连接代理(关键设计)
public class ConnectionProxy implements Connection {
private Connection realConnection;
private ConnectionPool pool;
// 包装实际连接
public ConnectionProxy(Connection real, ConnectionPool pool) {
this.realConnection = real;
this.pool = pool;
}
@Override
public void close() throws SQLException {
// 拦截close(),改为归还连接
pool.releaseConnection(this);
}
// 所有方法委托给真实连接
@Override
public Statement createStatement() throws SQLException {
return realConnection.createStatement();
}
// ... 其他方法类似
}
连接验证机制
private boolean validateConnection(Connection conn) {
try {
// 简单验证:执行一个轻量级查询
if (conn.isClosed()) return false;
Statement stmt = conn.createStatement();
stmt.execute("SELECT 1");
return true;
} catch (SQLException e) {
return false;
}
}
线程安全与连接超时
// 使用信号量控制并发获取连接
private Semaphore semaphore = new Semaphore(maxSize, true);
public Connection getConnectionWithTimeout(long timeout, TimeUnit unit)
throws SQLException, InterruptedException {
if (semaphore.tryAcquire(timeout, unit)) {
return getConnection();
}
throw new SQLException("获取连接超时");
}
完整流程图
[应用层] --getConnection()--> [连接池]
|
┌──────────────┴──────────────┐
↓ ↓
[空闲池有连接] [空闲池无连接]
| |
取连接 ─→ 验证有效否──→ 有效:返回 [判断连接数]
| | ↓
| 无效 [达到最大数?]
| ↓ / \
丢弃连接 创建新连接 [是] [否]
| | 等待/异常 创建新连接
└───────┴──────────┘
|
[返回连接给应用]
|
[应用使用连接,然后close()]
|
[close()被拦截]
|
┌─────────┴──────────┐
↓ ↓
[空闲池未满] [空闲池已满]
| |
放回空闲池 关闭连接
进阶优化点
- 连接泄露检测: 记录连接借出时间,超时自动回收
- 连接健康检查: 定时任务清理无效连接
- 扩展性: 支持不同数据源、连接属性配置
- 性能统计: 记录获取连接时间、命中率等指标
这个手写实现涵盖了连接池最核心的复用、代理、验证、线程安全逻辑,实际生产中的HikariCP、Druid等在此基础上增加了更多优化和监控功能。