一、连接池核心架构
1. 连接池整体架构图
text
复制
下载
┌─────────────────────────────────────────────────────────┐
│ 应用层(Application) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 连接池管理器(ConnectionPoolManager) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 空闲连接池 │ │ 活跃连接池 │ │ 连接工厂 │ │
│ │ (Idle Pool) │ │ (Active Pool)│ │ (Factory) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 数据库驱动(JDBC Driver) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 数据库服务器(Database) │
└─────────────────────────────────────────────────────────┘
2. 连接池三大核心组件
java
复制
下载
public interface ConnectionPool {
// 1. 连接工厂 - 创建物理连接
interface ConnectionFactory {
Connection create() throws SQLException;
boolean validate(Connection conn);
void destroy(Connection conn);
}
// 2. 连接包装器 - 代理真实连接
class PooledConnection implements Connection {
private Connection realConnection; // 真实JDBC连接
private ConnectionPool pool; // 所属连接池
private long lastUsedTime; // 最后使用时间
private volatile boolean isActive; // 是否活跃
@Override
public void close() throws SQLException {
// 重写close(),归还连接而不是关闭
if (isActive) {
pool.returnConnection(this);
}
}
}
// 3. 连接池管理器
class ConnectionPoolManager {
private BlockingQueue<PooledConnection> idleConnections;
private Set<PooledConnection> activeConnections;
private ConnectionFactory factory;
private PoolConfig config;
// 关键方法
public Connection getConnection() throws SQLException;
public void returnConnection(PooledConnection conn);
public void evictIdleConnections();
}
}
二、连接生命周期管理
1. 连接创建流程
java
复制
下载
public class HikariConnectionPool {
// 连接创建的完整流程
public Connection createConnection() throws SQLException {
long startTime = System.currentTimeMillis();
// 1. 驱动加载(首次使用时)
if (!isDriverLoaded()) {
loadJdbcDriver();
}
// 2. 建立物理连接
Properties props = new Properties();
props.setProperty("user", config.getUsername());
props.setProperty("password", config.getPassword());
props.setProperty("connectTimeout", String.valueOf(config.getConnectionTimeout()));
Connection rawConn = null;
try {
// 调用DriverManager获取连接
rawConn = DriverManager.getConnection(
config.getJdbcUrl(),
props
);
// 3. 连接后初始化
initializeConnection(rawConn);
// 4. 包装为池化连接
PooledConnection pooledConn = wrapConnection(rawConn);
// 5. 记录连接创建指标
recordConnectionCreateTime(System.currentTimeMillis() - startTime);
return pooledConn;
} catch (SQLException e) {
// 连接失败处理
log.error("创建数据库连接失败", e);
// 关闭可能已创建的部分连接
if (rawConn != null) {
quietlyClose(rawConn);
}
throw e;
}
}
private void initializeConnection(Connection conn) throws SQLException {
// 设置连接参数
conn.setAutoCommit(config.isAutoCommit());
conn.setTransactionIsolation(config.getTransactionIsolation());
conn.setReadOnly(config.isReadOnly());
// 设置会话变量(MySQL为例)
try (Statement stmt = conn.createStatement()) {
// 设置字符集
stmt.execute("SET NAMES utf8mb4");
// 设置时区
stmt.execute("SET time_zone = '+08:00'");
// 设置SQL模式
stmt.execute("SET sql_mode = 'STRICT_TRANS_TABLES'");
}
}
}
2. 连接获取流程
java
复制
下载
public class ConnectionPoolImpl {
public Connection getConnection() throws SQLException {
return getConnection(config.getConnectionTimeout());
}
public Connection getConnection(long timeout) throws SQLException {
long startTime = System.currentTimeMillis();
// 1. 检查连接池状态
if (isClosed()) {
throw new SQLException("连接池已关闭");
}
// 2. 从空闲队列获取(快速路径)
PooledConnection conn = idleConnections.poll();
if (conn != null) {
// 验证连接是否有效
if (validateConnection(conn)) {
activateConnection(conn);
return conn;
} else {
// 无效连接,销毁并继续尝试
destroyConnection(conn);
}
}
// 3. 如果未达到最大连接数,创建新连接
if (activeConnections.size() < config.getMaximumPoolSize()) {
try {
Connection newConn = createConnection();
activateConnection((PooledConnection) newConn);
return newConn;
} catch (SQLException e) {
// 创建失败,尝试获取已有连接
log.warn("创建新连接失败", e);
}
}
// 4. 等待空闲连接(阻塞或超时)
try {
conn = idleConnections.poll(timeout, TimeUnit.MILLISECONDS);
if (conn != null && validateConnection(conn)) {
activateConnection(conn);
return conn;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new SQLException("获取连接被中断", e);
}
// 5. 超时或获取失败
long elapsed = System.currentTimeMillis() - startTime;
throw new SQLTimeoutException(
String.format("获取连接超时(等待%dms,最大%dms)",
elapsed, timeout)
);
}
private boolean validateConnection(PooledConnection conn) {
// 验证连接是否有效的几种方式
try {
// 方式1:发送测试查询
if (config.getConnectionTestQuery() != null) {
try (Statement stmt = conn.createStatement()) {
stmt.execute(config.getConnectionTestQuery());
}
}
// 方式2:调用isValid方法(JDBC 4+)
else if (config.getValidationTimeout() > 0) {
return conn.isValid(config.getValidationTimeout());
}
// 方式3:简单检查连接是否关闭
else {
return !conn.isClosed();
}
// 检查连接是否超过最大生命周期
long maxLifetime = config.getMaxLifetime();
if (maxLifetime > 0) {
long age = System.currentTimeMillis() - conn.getCreateTime();
if (age > maxLifetime) {
log.debug("连接已超过最大生命周期: {}ms", age);
return false;
}
}
// 检查连接空闲时间
long idleTimeout = config.getIdleTimeout();
if (idleTimeout > 0) {
long idleTime = System.currentTimeMillis() - conn.getLastUsedTime();
if (idleTime > idleTimeout) {
log.debug("连接空闲时间过长: {}ms", idleTime);
return false;
}
}
return true;
} catch (SQLException e) {
log.debug("连接验证失败", e);
return false;
}
}
}
3. 连接归还流程
java
复制
下载
public class PooledConnection implements Connection {
@Override
public void close() throws SQLException {
// 关键:重写close()方法,归还到连接池
if (!isClosed) {
try {
// 1. 重置连接状态
resetConnectionState();
// 2. 检查连接是否仍然有效
if (!pool.validateConnection(this)) {
// 无效连接,直接销毁
pool.destroyConnection(this);
return;
}
// 3. 归还到空闲队列
pool.returnConnection(this);
// 4. 更新最后使用时间
this.lastUsedTime = System.currentTimeMillis();
} catch (SQLException e) {
// 归还失败,销毁连接
pool.destroyConnection(this);
throw e;
} finally {
this.isClosed = true;
}
}
}
private void resetConnectionState() throws SQLException {
// 重置自动提交
if (!getAutoCommit()) {
rollback(); // 回滚未提交的事务
setAutoCommit(true);
}
// 重置只读状态
if (isReadOnly()) {
setReadOnly(false);
}
// 重置事务隔离级别
if (getTransactionIsolation() != Connection.TRANSACTION_READ_COMMITTED) {
setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
}
// 关闭所有未关闭的Statement
closeAllOpenStatements();
// 清空警告链
clearWarnings();
}
}
public class ConnectionPoolManager {
public void returnConnection(PooledConnection conn) {
// 1. 从活跃集合移除
activeConnections.remove(conn);
// 2. 检查连接池是否已关闭
if (isClosed()) {
destroyConnection(conn);
return;
}
// 3. 检查空闲连接是否过多
if (idleConnections.size() >= config.getMinimumIdle()) {
// 空闲连接已足够,销毁这个连接
destroyConnection(conn);
return;
}
// 4. 放回空闲队列
boolean offered = idleConnections.offer(conn);
if (!offered) {
// 队列已满,销毁连接
destroyConnection(conn);
}
// 5. 通知等待线程
synchronized (this) {
this.notifyAll();
}
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
4. 连接销毁流程
java
复制
下载
public class ConnectionPoolManager {
public void destroyConnection(PooledConnection conn) {
if (conn == null) {
return;
}
try {
// 1. 从活跃集合中移除
activeConnections.remove(conn);
// 2. 从空闲队列中移除
idleConnections.remove(conn);
// 3. 关闭真实的物理连接
Connection realConn = conn.getRealConnection();
if (realConn != null && !realConn.isClosed()) {
realConn.close();
}
// 4. 记录指标
recordConnectionDestroy();
// 5. 如果连接池太小,补充新连接
maintainMinimumIdle();
} catch (SQLException e) {
log.warn("关闭数据库连接失败", e);
} finally {
// 6. 清理引用
conn.setRealConnection(null);
}
}
// 空闲连接驱逐线程
private class ConnectionEvictor implements Runnable {
@Override
public void run() {
while (!isClosed()) {
try {
Thread.sleep(config.getIdleTimeout() / 2);
// 检查所有空闲连接
List<PooledConnection> idleCopy =
new ArrayList<>(idleConnections);
for (PooledConnection conn : idleCopy) {
long idleTime = System.currentTimeMillis() - conn.getLastUsedTime();
// 检查空闲超时
if (idleTime > config.getIdleTimeout()) {
log.debug("驱逐空闲连接,空闲时间: {}ms", idleTime);
destroyConnection(conn);
continue;
}
// 检查最大生命周期
long age = System.currentTimeMillis() - conn.getCreateTime();
if (age > config.getMaxLifetime()) {
log.debug("驱逐过老连接,年龄: {}ms", age);
destroyConnection(conn);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
三、连接池核心算法
1. 连接池状态机
java
复制
下载
public class PooledConnection {
// 连接状态定义
enum ConnectionState {
IDLE, // 空闲状态,在池中等待使用
ACTIVE, // 活跃状态,正在被使用
VALIDATING, // 验证中
EVICTING, // 正在被驱逐
CLOSED // 已关闭
}
// 状态转换方法
public void markActive() {
if (state == ConnectionState.IDLE) {
state = ConnectionState.ACTIVE;
lastBorrowedTime = System.currentTimeMillis();
} else {
throw new IllegalStateException("无法从状态 " + state + " 转换到ACTIVE");
}
}
public void markIdle() {
if (state == ConnectionState.ACTIVE || state == ConnectionState.VALIDATING) {
state = ConnectionState.IDLE;
lastReturnedTime = System.currentTimeMillis();
} else {
throw new IllegalStateException("无法从状态 " + state + " 转换到IDLE");
}
}
}
// 连接池状态监控
public class PoolStats {
private final AtomicInteger totalConnections = new AtomicInteger();
private final AtomicInteger idleConnections = new AtomicInteger();
private final AtomicInteger activeConnections = new AtomicInteger();
private final AtomicLong connectionRequests = new AtomicLong();
private final AtomicLong connectionTimeouts = new AtomicLong();
// 关键指标计算
public double getConnectionUsageRatio() {
int total = totalConnections.get();
int active = activeConnections.get();
return total > 0 ? (double) active / total : 0.0;
}
public double getConnectionWaitRatio() {
long requests = connectionRequests.get();
long timeouts = connectionTimeouts.get();
return requests > 0 ? (double) timeouts / requests : 0.0;
}
}
2. 连接泄漏检测
java
复制
下载
public class ConnectionLeakDetection {
private final ThreadLocal<LeakTask> leakTaskHolder = new ThreadLocal<>();
private final ScheduledExecutorService leakExecutor;
private final long leakDetectionThreshold; // 泄漏检测阈值
class LeakTask {
final PooledConnection connection;
final long borrowTime;
final StackTraceElement[] borrowStackTrace;
LeakTask(PooledConnection conn) {
this.connection = conn;
this.borrowTime = System.currentTimeMillis();
this.borrowStackTrace = Thread.currentThread().getStackTrace();
}
}
// 借出连接时开始监控
public void startLeakDetection(PooledConnection conn) {
if (leakDetectionThreshold > 0) {
LeakTask task = new LeakTask(conn);
leakTaskHolder.set(task);
// 调度泄漏检查
leakExecutor.schedule(() -> {
LeakTask currentTask = leakTaskHolder.get();
if (currentTask != null && currentTask.connection == conn) {
// 连接仍未归还,可能泄漏
reportPotentialLeak(conn, currentTask);
}
}, leakDetectionThreshold, TimeUnit.MILLISECONDS);
}
}
// 归还连接时取消监控
public void stopLeakDetection(PooledConnection conn) {
leakTaskHolder.remove();
}
private void reportPotentialLeak(PooledConnection conn, LeakTask task) {
long heldTime = System.currentTimeMillis() - task.borrowTime;
StringBuilder sb = new StringBuilder();
sb.append("检测到可能的连接泄漏!\n");
sb.append("连接已持有: ").append(heldTime).append("ms\n");
sb.append("借出时的堆栈跟踪:\n");
for (StackTraceElement element : task.borrowStackTrace) {
sb.append(" at ").append(element).append("\n");
}
log.warn(sb.toString());
// 强制关闭泄漏的连接
if (config.isRemoveAbandoned()) {
conn.forceClose();
}
}
}
3. 连接池大小动态调整
java
复制
下载
public class DynamicPoolResizer {
private final ConnectionPool pool;
private final ScheduledExecutorService resizer;
private final long housekeepingPeriodMs;
// 基于负载的动态调整策略
public void startDynamicResizing() {
resizer.scheduleAtFixedRate(() -> {
try {
adjustPoolSizeBasedOnLoad();
} catch (Exception e) {
log.error("动态调整连接池大小失败", e);
}
}, housekeepingPeriodMs, housekeepingPeriodMs, TimeUnit.MILLISECONDS);
}
private void adjustPoolSizeBasedOnLoad() {
PoolStats stats = pool.getStats();
// 1. 计算当前负载指标
double usageRatio = stats.getConnectionUsageRatio();
double waitRatio = stats.getConnectionWaitRatio();
long avgWaitTime = stats.getAverageWaitTime();
// 2. 基于使用率的调整
int currentSize = pool.getTotalConnections();
int activeConnections = stats.getActiveConnections();
if (usageRatio > 0.8 && waitRatio > 0.1) {
// 高负载,需要扩容
int newSize = Math.min(
currentSize * 2,
pool.getConfig().getMaximumPoolSize()
);
if (newSize > currentSize) {
log.info("连接池负载过高,从 {} 扩容到 {}", currentSize, newSize);
pool.resize(newSize);
}
}
else if (usageRatio < 0.3 && currentSize > pool.getConfig().getMinimumIdle()) {
// 低负载,可以缩容
int newSize = Math.max(
activeConnections * 2,
pool.getConfig().getMinimumIdle()
);
if (newSize < currentSize) {
log.info("连接池负载较低,从 {} 缩容到 {}", currentSize, newSize);
pool.resize(newSize);
}
}
// 3. 基于时间段的调整(考虑业务峰值)
adjustForTimeOfDay();
}
private void adjustForTimeOfDay() {
Calendar cal = Calendar.getInstance();
int hour = cal.get(Calendar.HOUR_OF_DAY);
// 业务高峰时段(如上午9-11点,下午2-4点)
boolean isPeakHour = (hour >= 9 && hour < 11) || (hour >= 14 && hour < 16);
if (isPeakHour) {
// 高峰时段保持更多连接
pool.setMinimumIdle(Math.max(
pool.getConfig().getMinimumIdle(),
pool.getConfig().getMaximumPoolSize() / 2
));
} else {
// 低谷时段减少最小空闲连接
pool.setMinimumIdle(Math.min(
pool.getConfig().getMinimumIdle(),
pool.getConfig().getMaximumPoolSize() / 4
));
}
}
}
四、主流连接池实现对比
1. HikariCP 核心实现
java
复制
下载
// HikariCP 快速获取连接的实现
public class HikariPool {
// 使用无锁的ConcurrentBag实现高性能连接管理
private final ConcurrentBag<PoolEntry> connectionBag;
// 快速路径(FastPath)
public Connection getConnection() throws SQLException {
// 1. 尝试从ThreadLocal获取(避免竞争)
PoolEntry entry = fastPathPoolEntry.get();
if (entry != null && entry.state == STATE_NOT_IN_USE) {
if (entry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
metricsTracker.recordBorrowStats(entry, startTime);
return entry.createProxyConnection();
}
}
// 2. 从ConcurrentBag借出
entry = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS);
if (entry != null) {
// 记录到ThreadLocal以便下次快速获取
fastPathPoolEntry.set(entry);
// 验证连接
if (!isConnectionAlive(entry.connection)) {
closeConnection(entry);
throw new SQLException("连接验证失败");
}
return entry.createProxyConnection();
}
throw new SQLTimeoutException("获取连接超时");
}
// ConcurrentBag的核心数据结构
class ConcurrentBag<T extends IConcurrentBagEntry> {
// 三个关键数据结构:
// 1. sharedList: CopyOnWriteArrayList,所有连接的共享列表
// 2. threadList: ThreadLocal<LinkedList>,线程本地连接列表
// 3. handoffQueue: SynchronousQueue,用于连接传递
public T borrow(long timeout, TimeUnit timeUnit) {
// 优先从ThreadLocal获取
List<Object> list = threadList.get();
if (list != null) {
for (int i = list.size() - 1; i >= 0; i--) {
T entry = (T) list.remove(i);
if (entry.state().compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
return entry;
}
}
}
// ThreadLocal没有,从共享列表获取
final CopyOnWriteArrayList<T> shared = sharedList;
final int size = shared.size();
for (int i = 0; i < size; i++) {
T entry = shared.get(i);
if (entry.state().compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
return entry;
}
}
// 共享列表也没有,等待其他线程释放
return handoffQueue.poll(timeout, timeUnit);
}
}
}
2. Druid 高级特性
java
复制
下载
// Druid 的监控和过滤器机制
public class DruidDataSource {
// 丰富的监控统计
private final DruidDataSourceStatLogger statLogger;
private final Map<String, Object> statMap = new ConcurrentHashMap<>();
// 过滤器链
private Filter[] filters;
public Connection getConnection() throws SQLException {
// 记录开始时间
long startTime = System.currentTimeMillis();
try {
Connection conn = super.getConnection();
// 过滤器前置处理
for (Filter filter : filters) {
conn = filter.connection_connectBefore(conn);
}
// 记录统计信息
recordConnectionObtainTime(System.currentTimeMillis() - startTime);
return conn;
} catch (SQLException e) {
// 记录错误统计
incrementErrorCount();
throw e;
}
}
// SQL监控
class DruidStatement extends FilterChainImpl {
@Override
public ResultSet executeQuery(String sql) throws SQLException {
// 记录SQL开始执行
long startTime = System.currentTimeMillis();
String formattedSql = formatSql(sql);
try {
ResultSet rs = super.executeQuery(sql);
// 记录执行成功
recordSqlSuccess(formattedSql, System.currentTimeMillis() - startTime);
return rs;
} catch (SQLException e) {
// 记录执行失败
recordSqlError(formattedSql, e, System.currentTimeMillis() - startTime);
throw e;
}
}
}
// WallFilter - SQL防火墙
class WallFilter extends FilterAdapter {
private WallProvider wallProvider;
@Override
public PreparedStatement connection_prepareStatement(
Connection conn, String sql) throws SQLException {
// 检查SQL是否合法
if (!wallProvider.checkValid(sql)) {
throw new SQLException("SQL被防火墙拦截: " + sql);
}
// 检查是否超过最大更新行数
if (wallProvider.isDenyUpdate(sql)) {
throw new SQLException("更新操作被限制");
}
return super.connection_prepareStatement(conn, sql);
}
}
}
3. 连接池性能对比
java
复制
下载
// 性能测试结果对比(基于实际压测数据)
public class ConnectionPoolBenchmark {
// 关键性能指标对比表
class BenchmarkResults {
/*
连接池类型 QPS 平均延迟 99分位延迟 内存占用 功能丰富度
---------- -------- -------- ---------- -------- ----------
HikariCP 150,000 0.8ms 2.1ms 低 中等
Druid 120,000 1.2ms 3.5ms 中 极高
Tomcat JDBC 100,000 1.5ms 4.2ms 低 低
C3P0 80,000 2.1ms 6.8ms 高 中等
DBCP 90,000 1.8ms 5.3ms 中 中等
*/
}
// 选择建议
class SelectionGuide {
/*
场景 推荐连接池 理由
---------------- ------------ --------------------------------
极致性能 HikariCP 最快的连接池,Spring Boot默认
需要监控和SQL分析 Druid 强大的监控和防火墙功能
Spring Boot应用 HikariCP 默认集成,配置简单
传统企业应用 Druid 丰富的企业级功能
简单场景 Tomcat JDBC 轻量级,Tomcat内置
遗留系统 C3P0/DBCP 兼容老系统
*/
}
}
五、生产环境最佳实践
1. 配置参数优化
yaml
复制
下载
# application.yml 中的连接池配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/app_db?useSSL=false&characterEncoding=utf8
username: app_user
password: ${DB_PASSWORD}
hikari:
# 连接池大小
maximum-pool-size: 20 # 最大连接数 = (核心数 * 2) + 磁盘数
minimum-idle: 10 # 最小空闲连接
# 连接生命周期
max-lifetime: 1800000 # 30分钟(避免数据库连接超时)
idle-timeout: 600000 # 10分钟(MySQL wait_timeout=8h)
connection-timeout: 30000 # 30秒获取连接超时
# 连接验证
connection-test-query: SELECT 1 # MySQL测试查询
validation-timeout: 5000 # 5秒验证超时
# 性能优化
connection-init-sql: SET NAMES utf8mb4
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
2. 监控与告警配置
java
复制
下载
@Configuration
public class ConnectionPoolMonitoring {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCustomizer(
DataSource dataSource) {
return registry -> {
// HikariCP监控指标
if (dataSource instanceof HikariDataSource) {
HikariDataSource hikari = (HikariDataSource) dataSource;
HikariPoolMXBean pool = hikari.getHikariPoolMXBean();
Gauge.builder("db.pool.active.connections",
pool::getActiveConnections)
.description("活跃连接数")
.register(registry);
Gauge.builder("db.pool.idle.connections",
pool::getIdleConnections)
.description("空闲连接数")
.register(registry);
Gauge.builder("db.pool.total.connections",
pool::getTotalConnections)
.description("总连接数")
.register(registry);
Gauge.builder("db.pool.threads.awaiting",
pool::getThreadsAwaitingConnection)
.description("等待连接的线程数")
.register(registry);
}
// Druid监控指标
if (dataSource instanceof DruidDataSource) {
DruidDataSource druid = (DruidDataSource) dataSource;
Gauge.builder("db.druid.active.count",
druid::getActiveCount)
.description("Druid活跃连接数")
.register(registry);
Gauge.builder("db.druid.pooling.count",
druid::getPoolingCount)
.description("Druid池中连接数")
.register(registry);
}
};
}
// 告警规则配置
@Bean
public MonitoringAlerts monitoringAlerts() {
return MonitoringAlerts.builder()
.addAlert(AlertRule.builder()
.metric("db.pool.active.connections")
.threshold(0.8) // 使用率超过80%
.duration(Duration.ofMinutes(5))
.severity(AlertSeverity.WARNING)
.message("数据库连接池使用率过高")
.build())
.addAlert(AlertRule.builder()
.metric("db.pool.threads.awaiting")
.threshold(10) // 超过10个线程等待
.duration(Duration.ofMinutes(2))
.severity(AlertSeverity.CRITICAL)
.message("数据库连接池出现等待队列")
.build())
.build();
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
3. 故障排查与调试
java
复制
下载
public class ConnectionPoolTroubleshooting {
// 诊断连接泄漏
public void diagnoseConnectionLeak() {
// 1. 启用泄漏检测
HikariConfig config = new HikariConfig();
config.setLeakDetectionThreshold(30000); // 30秒
// 2. 定期检查连接状态
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
HikariPoolMXBean pool = hikariDataSource.getHikariPoolMXBean();
log.info("连接池状态 - 活跃: {}, 空闲: {}, 总计: {}, 等待: {}",
pool.getActiveConnections(),
pool.getIdleConnections(),
pool.getTotalConnections(),
pool.getThreadsAwaitingConnection());
// 检查连接持有时间
checkConnectionHoldTime();
}, 0, 60, TimeUnit.SECONDS);
}
// 分析慢SQL
public void analyzeSlowQueries(DataSource dataSource) {
if (dataSource instanceof DruidDataSource) {
DruidDataSource druid = (DruidDataSource) dataSource;
// 获取慢SQL列表
List<Map<String, Object>> slowSqls = druid.getDataSourceStat()
.getSqlStatMap()
.values()
.stream()
.filter(sqlStat -> sqlStat.getExecuteMillisTotal() /
Math.max(1, sqlStat.getExecuteCount()) > 1000) // 超过1秒
.sorted(Comparator.comparingLong(
sqlStat -> -sqlStat.getExecuteMillisTotal()))
.limit(10)
.map(sqlStat -> {
Map<String, Object> map = new HashMap<>();
map.put("sql", sqlStat.getSql());
map.put("execution_count", sqlStat.getExecuteCount());
map.put("total_time", sqlStat.getExecuteMillisTotal());
map.put("avg_time", sqlStat.getExecuteMillisTotal() /
Math.max(1, sqlStat.getExecuteCount()));
return map;
})
.collect(Collectors.toList());
log.warn("慢SQL TOP 10: {}", slowSqls);
}
}
// 连接池健康检查端点
@RestController
@RequestMapping("/health")
public class ConnectionPoolHealthController {
@GetMapping("/connection-pool")
public Map<String, Object> checkConnectionPool() {
Map<String, Object> health = new LinkedHashMap<>();
try (Connection conn = dataSource.getConnection()) {
// 测试连接
try (Statement stmt = conn.createStatement()) {
stmt.execute("SELECT 1");
}
health.put("status", "UP");
health.put("database", conn.getMetaData().getDatabaseProductName());
// 连接池详情
if (dataSource instanceof HikariDataSource) {
HikariPoolMXBean pool = ((HikariDataSource) dataSource)
.getHikariPoolMXBean();
health.put("activeConnections", pool.getActiveConnections());
health.put("idleConnections", pool.getIdleConnections());
health.put("totalConnections", pool.getTotalConnections());
health.put("threadsAwaiting", pool.getThreadsAwaitingConnection());
}
} catch (SQLException e) {
health.put("status", "DOWN");
health.put("error", e.getMessage());
}
return health;
}
}
}
六、高级主题与未来趋势
1. 响应式连接池
java
复制
下载
// R2DBC 响应式数据库连接池
public class ReactiveConnectionPool {
private final ConnectionPool pool;
public Mono<Connection> getConnection() {
return Mono.create(sink -> {
try {
Connection conn = pool.getConnection();
sink.success(conn);
} catch (SQLException e) {
sink.error(e);
}
}).subscribeOn(Schedulers.elastic());
}
// 响应式连接包装器
class ReactiveConnection implements Connection {
private final Connection delegate;
public Flux<Result> executeQuery(String sql) {
return Flux.create(sink -> {
try {
Statement stmt = delegate.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// 流式处理结果集
while (rs.next()) {
if (!sink.isCancelled()) {
sink.next(convertToResult(rs));
} else {
break;
}
}
sink.complete();
} catch (SQLException e) {
sink.error(e);
}
});
}
}
}
2. 多数据源路由
java
复制
下载
// 基于读写分离的动态数据源路由
public class DynamicDataSource extends AbstractRoutingDataSource {
private DataSource writeDataSource;
private List<DataSource> readDataSources;
private AtomicInteger readCounter = new AtomicInteger(0);
@Override
protected Object determineCurrentLookupKey() {
// 根据上下文决定使用哪个数据源
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
// 只读事务使用读库
int index = readCounter.getAndIncrement() % readDataSources.size();
return "read_" + index;
} else {
// 写事务使用写库
return "write";
}
}
// 连接池分组管理
class DataSourceGroup {
private String name;
private DataSource dataSource;
private ConnectionPool pool;
private Health health;
// 健康检查
public boolean isHealthy() {
try (Connection conn = dataSource.getConnection()) {
return conn.isValid(5);
} catch (SQLException e) {
return false;
}
}
// 负载统计
public double getLoadFactor() {
PoolStats stats = pool.getStats();
return stats.getConnectionUsageRatio();
}
}
}
3. 云原生连接池
java
复制
下载
// 容器环境感知的连接池
public class CloudNativeConnectionPool {
private final KubernetesClient k8sClient;
private final String namespace;
private final String serviceName;
// 自动发现数据库端点
public List<Endpoint> discoverDatabaseEndpoints() {
// 1. 通过Kubernetes Service发现
Service service = k8sClient.services()
.inNamespace(namespace)
.withName(serviceName)
.get();
// 2. 获取Pod端点
Endpoints endpoints = k8sClient.endpoints()
.inNamespace(namespace)
.withName(serviceName)
.get();
return endpoints.getSubsets().stream()
.flatMap(subset -> subset.getAddresses().stream())
.map(address -> new Endpoint(
address.getIp(),
service.getSpec().getPorts().get(0).getPort()
))
.collect(Collectors.toList());
}
// 基于QoS的连接池调整
public void adjustPoolByQoS() {
// 获取Pod资源限制
Pod pod = k8sClient.pods()
.inNamespace(namespace)
.withName(System.getenv("HOSTNAME"))
.get();
// 计算建议的连接池大小
Quantity memory = pod.getSpec().getContainers().get(0)
.getResources().getLimits().get("memory");
Quantity cpu = pod.getSpec().getContainers().get(0)
.getResources().getLimits().get("cpu");
// 基于资源计算连接数
long memoryMB = memory.getAmount().longValue();
long cpuMillis = cpu.getAmount().multiply(BigDecimal.valueOf(1000)).longValue();
// 经验公式:每连接 ≈ 5MB内存
int maxConnections = (int) Math.min(
memoryMB / 5,
cpuMillis / 100 // 每连接 ≈ 100ms CPU时间
);
// 动态调整连接池大小
hikariConfig.setMaximumPoolSize(maxConnections);
}
}
七、总结
📊 连接池核心要点总结
-
核心价值:
-
减少连接创建开销(TCP三次握手、认证等)
-
控制数据库连接数,避免过载
-
提供连接复用,提高性能
-
-
关键参数:
java
复制
下载
// 必须合理配置的四大参数 maximumPoolSize: // 最大连接数 = (CPU核心数 * 2) + 有效磁盘数 minimumIdle: // 最小空闲连接 = maximumPoolSize / 4 maxLifetime: // 最大生命周期 < 数据库wait_timeout connectionTimeout: // 获取连接超时时间 -
监控指标:
-
活跃连接数(Active Connections)
-
空闲连接数(Idle Connections)
-
等待线程数(Threads Awaiting)
-
连接获取时间(Connection Obtain Time)
-
-
故障排查:
-
连接泄漏:启用leakDetectionThreshold
-
连接池满:检查maximumPoolSize和业务逻辑
-
慢查询:分析SQL执行时间
-
连接失效:调整validationQuery和testOnBorrow
-
🚀 未来发展趋势
-
响应式连接池:适应Reactive编程模型
-
智能连接池:基于AI的自动调优
-
多云连接池:跨云数据库的智能路由
-
Serverless连接池:适应无服务器架构
记住:连接池不是银弹,正确的配置需要结合具体的业务场景、数据库特性和系统负载。定期监控和调优是保证连接池高效运行的关键。