本文目录导读:

我来提供一个完整的Java数据库连接池监控案例,包括HikariCP、Druid两种主流连接池的监控实现。
项目结构
db-pool-monitor/
├── pom.xml
├── src/main/java/com/example/monitor/
│ ├── config/
│ │ ├── HikariCPConfig.java
│ │ ├── DruidConfig.java
│ │ └── DataSourceConfig.java
│ ├── monitor/
│ │ ├── ConnectionPoolMonitor.java
│ │ ├── MonitorScheduler.java
│ │ └── AlertService.java
│ ├── controller/
│ │ ├── PoolMonitorController.java
│ │ └── HealthCheckController.java
│ ├── service/
│ │ ├── DataSourceService.java
│ │ └── MetricsCollector.java
│ └── model/
│ ├── PoolMetrics.java
│ └── AlertMessage.java
Maven依赖配置
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
<!-- Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Prometheus Metrics -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
连接池配置
HikariCP配置类
package com.example.monitor.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.support.RegistrationPolicy;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
public class HikariCPConfig {
@Value("${spring.datasource.url}")
private String jdbcUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.hikari.maximum-pool-size:10}")
private int maxPoolSize;
@Bean
public DataSource hikariDataSource(MeterRegistry meterRegistry) {
HikariConfig config = new HikariConfig();
// 数据库连接配置
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
// 连接池配置
config.setPoolName("HikariPool-Main");
config.setMaximumPoolSize(maxPoolSize);
config.setMinimumIdle(5);
config.setIdleTimeout(300000); // 5分钟
config.setConnectionTimeout(30000); // 30秒
config.setMaxLifetime(1800000); // 30分钟
config.setConnectionTestQuery("SELECT 1");
// 监控配置
config.setMetricRegistry(meterRegistry);
config.setHealthCheckRegistry(new com.codahale.metrics.health.HealthCheckRegistry());
// JMX监控
Properties props = new Properties();
props.setProperty("dataSource.cachePrepStmts", "true");
props.setProperty("dataSource.prepStmtCacheSize", "250");
props.setProperty("dataSource.prepStmtCacheSqlLimit", "2048");
config.setDataSourceProperties(props);
return new HikariDataSource(config);
}
@Bean
public MBeanExporter exporter() {
MBeanExporter exporter = new MBeanExporter();
exporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);
return exporter;
}
}
Druid配置类
package com.example.monitor.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfig {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Bean
public DataSource druidDataSource() throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
// 基础连接信息
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
// 连接池配置
dataSource.setInitialSize(5);
dataSource.setMinIdle(5);
dataSource.setMaxActive(20);
dataSource.setMaxWait(60000);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setMinEvictableIdleTimeMillis(300000);
dataSource.setValidationQuery("SELECT 1");
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
// 监控配置
dataSource.setFilters("stat,wall,log4j2");
dataSource.setUseGlobalDataSourceStat(true);
dataSource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");
// 开启PSCache
dataSource.setPoolPreparedStatements(true);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
return dataSource;
}
@Bean
public ServletRegistrationBean<StatViewServlet> statViewServlet() {
ServletRegistrationBean<StatViewServlet> reg = new ServletRegistrationBean<>(
new StatViewServlet(), "/druid/*");
// 设置监控页面访问权限
reg.addInitParameter("loginUsername", "admin");
reg.addInitParameter("loginPassword", "admin123");
reg.addInitParameter("resetEnable", "false");
reg.addInitParameter("allow", "127.0.0.1"); // IP白名单
return reg;
}
@Bean
public FilterRegistrationBean<WebStatFilter> webStatFilter() {
FilterRegistrationBean<WebStatFilter> reg = new FilterRegistrationBean<>();
reg.setFilter(new WebStatFilter());
reg.setUrlPatterns(Arrays.asList("/*"));
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*,/static/*");
reg.setInitParameters(initParams);
return reg;
}
}
监控模型类
package com.example.monitor.model;
import lombok.Data;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.util.Map;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PoolMetrics {
// 基础信息
private String poolName;
private String poolType; // HIKARICP / DRUID
private long timestamp;
// 连接池状态
private int activeConnections;
private int idleConnections;
private int totalConnections;
private int maxConnections;
private int minConnections;
private int waitingThreads;
// 连接池配置
private long connectionTimeout;
private long validationTimeout;
private long maxLifetime;
private long idleTimeout;
// 性能指标
private long totalConnectionsCreated;
private long totalConnectionsClosed;
private long totalConnectionsAcquired;
private long totalConnectionsReleased;
// 耗时统计
private long avgConnectionTimeMs;
private long maxConnectionTimeMs;
private long connectionCreationTimeMs;
// 错误统计
private long connectionErrors;
private long statementErrors;
// 使用率
private double usageRatio;
private double waitRate;
// Druid特有指标
private Long activePeak;
private Long activePeakTime;
private Long poolingCount;
private Long discardCount;
private Long waitThreadCount;
private Long waitCount;
private Long notEmptyWaitCount;
private Long notEmptyWaitNanos;
public Map<String, Object> toMap() {
return Map.of(
"poolName", poolName,
"poolType", poolType,
"activeConnections", activeConnections,
"idleConnections", idleConnections,
"totalConnections", totalConnections,
"maxConnections", maxConnections,
"waitingThreads", waitingThreads,
"usageRatio", usageRatio,
"waitRate", waitRate
);
}
}
监控核心逻辑
package com.example.monitor.monitor;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.monitor.model.PoolMetrics;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.metrics.PoolStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Component
public class ConnectionPoolMonitor {
private static final Logger logger = LoggerFactory.getLogger(ConnectionPoolMonitor.class);
@Autowired
private DataSource primaryDataSource;
@Autowired(required = false)
private HikariDataSource hikariDataSource;
@Autowired(required = false)
private DruidDataSource druidDataSource;
/**
* 收集HikariCP连接池指标
*/
public PoolMetrics collectHikariMetrics() {
if (hikariDataSource == null) {
return null;
}
PoolStats poolStats = hikariDataSource.getHikariPoolMXBean() != null ?
hikariDataSource.getHikariPoolMXBean() : null;
if (poolStats == null) {
logger.warn("HikariCP pool stats not available");
return null;
}
PoolStats stats = poolStats;
int maxConnections = hikariDataSource.getMaximumPoolSize();
int activeConnections = stats.getActiveConnections();
int idleConnections = stats.getIdleConnections();
return PoolMetrics.builder()
.poolName("HikariPool-Main")
.poolType("HIKARICP")
.timestamp(System.currentTimeMillis())
.activeConnections(activeConnections)
.idleConnections(idleConnections)
.totalConnections(activeConnections + idleConnections)
.maxConnections(maxConnections)
.waitingThreads(stats.getPendingThreads())
.connectionTimeout(hikariDataSource.getConnectionTimeout())
.maxLifetime(hikariDataSource.getMaxLifetime())
.totalConnectionsCreated(stats.getTotalConnections())
.totalConnectionsClosed(stats.getTotalConnections() - activeConnections - idleConnections)
.usageRatio((double) activeConnections / maxConnections)
.build();
}
/**
* 收集Druid连接池指标
*/
public PoolMetrics collectDruidMetrics() {
if (druidDataSource == null) {
return null;
}
try {
return PoolMetrics.builder()
.poolName("DruidPool-Main")
.poolType("DRUID")
.timestamp(System.currentTimeMillis())
.activeConnections(druidDataSource.getActiveCount())
.idleConnections(druidDataSource.getPoolingCount())
.totalConnections(druidDataSource.getActiveCount() + druidDataSource.getPoolingCount())
.maxConnections(druidDataSource.getMaxActive())
.minConnections(druidDataSource.getMinIdle())
.waitingThreads(druidDataSource.getWaitThreadCount())
.activePeak(druidDataSource.getActivePeak())
.activePeakTime(druidDataSource.getActivePeakTime())
.poolingCount((long) druidDataSource.getPoolingCount())
.discardCount(druidDataSource.getDiscardCount())
.waitCount(druidDataSource.getWaitCount())
.waitThreadCount((long) druidDataSource.getWaitThreadCount())
.notEmptyWaitCount(druidDataSource.getNotEmptyWaitCount())
.status(druidDataSource.isClosed() ? "closed" : "active")
.usageRatio((double) druidDataSource.getActiveCount() / druidDataSource.getMaxActive())
.build();
} catch (Exception e) {
logger.error("Failed to collect Druid metrics", e);
return null;
}
}
/**
* 执行健康检查
*/
public Map<String, Object> healthCheck() {
Map<String, Object> result = new HashMap<>();
// 检查HikariCP
if (hikariDataSource != null) {
Map<String, Object> hikariHealth = new HashMap<>();
try {
hikariHealth.put("status", "UP");
hikariHealth.put("activeConnections", hikariDataSource.getHikariPoolMXBean().getActiveConnections());
hikariHealth.put("idleConnections", hikariDataSource.getHikariPoolMXBean().getIdleConnections());
// 测试连接
long start = System.currentTimeMillis();
try (var conn = hikariDataSource.getConnection()) {
hikariHealth.put("connectionTestTime", System.currentTimeMillis() - start - start);
hikariHealth.put("connectionValid", conn.isValid(5));
}
} catch (Exception e) {
hikariHealth.put("status", "DOWN");
hikariHealth.put("error", e.getMessage());
}
result.put("hikari", hikariHealth);
}
// 检查Druid
if (druidDataSource != null) {
Map<String, Object> druidHealth = new HashMap<>();
try {
druidHealth.put("status", "UP");
druidHealth.put("activeConnections", druidDataSource.getActiveCount());
druidHealth.put("poolingCount", druidDataSource.getPoolingCount());
// 测试连接
long start = System.currentTimeMillis();
try (var conn = druidDataSource.getConnection()) {
druidHealth.put("connectionTestTime", System.currentTimeMillis() - start);
druidHealth.put("connectionValid", conn.isValid(5));
}
} catch (Exception e) {
druidHealth.put("status", "DOWN");
druidHealth.put("error", e.getMessage());
}
result.put("druid", druidHealth);
}
return result;
}
/**
* 创建监控告警信息
*/
static class AlertService {
private static final Logger logger = LoggerFactory.getLogger(AlertService.class);
public void alert(PoolMetrics metrics) {
// 连接池使用率告警
if (metrics.getUsageRatio() > 0.8) {
logger.error("连接池使用率过高!Pool: {}, Usage: {}%",
metrics.getPoolName(),
String.format("%.2f", metrics.getUsageRatio() * 100));
}
// 等待线程数告警
if (metrics.getWaitingThreads() > 10) {
logger.error("等待线程数过多!Pool: {}, Waiting: {}",
metrics.getPoolName(),
metrics.getWaitingThreads());
}
// 活跃连接接近上限
if (metrics.getActiveConnections() >= metrics.getMaxConnections() * 0.9) {
logger.warn("活跃连接数接近上限!Pool: {}, Active: {}, Max: {}",
metrics.getPoolName(),
metrics.getActiveConnections(),
metrics.getMaxConnections());
}
}
}
}
定时监控调度器
package com.example.monitor.monitor;
import com.example.monitor.model.PoolMetrics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentLinkedQueue;
@Component
@EnableScheduling
public class MonitorScheduler {
private static final Logger logger = LoggerFactory.getLogger(MonitorScheduler.class);
@Autowired
private ConnectionPoolMonitor poolMonitor;
@Autowired
private AlertService alertService;
private final ConcurrentLinkedQueue<PoolMetrics> metricsHistory = new ConcurrentLinkedQueue<>();
private static final int MAX_HISTORY_SIZE = 1000;
/**
* 定时采集连接池指标(每10秒)
*/
@Scheduled(fixedDelay = 10000)
public void collectMetrics() {
logger.debug("开始采集连接池指标...");
PoolMetrics hikariMetrics = poolMonitor.collectHikariMetrics();
if (hikariMetrics != null) {
addToHistory(hikariMetrics);
alertService.alert(hikariMetrics);
logMetrics(hikariMetrics);
}
PoolMetrics druidMetrics = poolMonitor.collectDruidMetrics();
if (druidMetrics != null) {
addToHistory(druidMetrics);
alertService.alert(druidMetrics);
logMetrics(druidMetrics);
}
}
/**
* 每小时清理历史数据
*/
@Scheduled(cron = "0 0 * * * ?")
public void cleanupHistory() {
long cutoffTime = System.currentTimeMillis() - 24 * 60 * 60 * 1000; // 保留24小时
metricsHistory.removeIf(metrics -> metrics.getTimestamp() < cutoffTime);
logger.info("清理完成,当前历史数据数量: {}", metricsHistory.size());
}
private void addToHistory(PoolMetrics metrics) {
metricsHistory.offer(metrics);
if (metricsHistory.size() > MAX_HISTORY_SIZE) {
metricsHistory.poll();
}
}
private void logMetrics(PoolMetrics metrics) {
logger.info("连接池监控 - Pool: {}, Type: {}, Active: {}, Idle: {}, Total: {}, Max: {}, Waiting: {}",
metrics.getPoolName(),
metrics.getPoolType(),
metrics.getActiveConnections(),
metrics.getIdleConnections(),
metrics.getTotalConnections(),
metrics.getMaxConnections(),
metrics.getWaitingThreads());
}
public ConcurrentLinkedQueue<PoolMetrics> getMetricsHistory() {
return metricsHistory;
}
public static class AlertService {
public void alert(PoolMetrics metrics) {
// 告警逻辑
if (metrics.getUsageRatio() > 0.8) {
logger.error("Connection pool usage ratio high: {}%",
String.format("%.2f", metrics.getUsageRatio() * 100));
}
}
}
}
API控制器
package com.example.monitor.controller;
import com.example.monitor.model.PoolMetrics;
import com.example.monitor.monitor.ConnectionPoolMonitor;
import com.example.monitor.monitor.MonitorScheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/monitor")
public class PoolMonitorController {
@Autowired
private ConnectionPoolMonitor poolMonitor;
@Autowired
private MonitorScheduler monitorScheduler;
/**
* 获取连接池实时指标
*/
@GetMapping("/metrics")
public ResponseEntity<Map<String, Object>> getMetrics() {
Map<String, Object> result = new HashMap<>();
PoolMetrics hikariMetrics = poolMonitor.collectHikariMetrics();
PoolMetrics druidMetrics = poolMonitor.collectDruidMetrics();
result.put("hikari", hikariMetrics);
result.put("druid", druidMetrics);
result.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(result);
}
/**
* 获取连接池健康检查状态
*/
@GetMapping("/health")
public ResponseEntity<Map<String, Object>> getHealth() {
return ResponseEntity.ok(poolMonitor.healthCheck());
}
/**
* 获取历史监控数据
*/
@GetMapping("/history")
public ResponseEntity<Map<String, Object>> getHistory(
@RequestParam(defaultValue = "10") int limit) {
Map<String, Object> result = new HashMap<>();
List<PoolMetrics> hikariHistory = monitorScheduler.getMetricsHistory()
.stream()
.filter(m -> "HIKARICP".equals(m.getPoolType()))
.limit(limit)
.collect(Collectors.toList());
List<PoolMetrics> druidHistory = monitorScheduler.getMetricsHistory()
.stream()
.filter(m -> "DRUID".equals(m.getPoolType()))
.limit(limit)
.collect(Collectors.toList());
result.put("hikari_history", hikariHistory);
result.put("druid_history", druidHistory);
result.put("total_records", monitorScheduler.getMetricsHistory().size());
return ResponseEntity.ok(result);
}
/**
* 连接池压力测试接口
*/
@PostMapping("/stress-test")
public ResponseEntity<Map<String, Object>> stressTest(
@RequestParam(defaultValue = "100") int iterations,
@RequestParam(defaultValue = "100") int delayMs) {
Map<String, Object> result = new HashMap<>();
List<Long> connectionTimes = new java.util.ArrayList<>();
for (int i = 0; i < iterations; i++) {
long start = System.nanoTime();
// 获取连接并执行简单查询
try (var conn = poolMonitor.getDataSource().getConnection();
var stmt = conn.createStatement();
var rs = stmt.executeQuery("SELECT 1")) {
if (rs.next()) {
long duration = (System.nanoTime() - start) / 1000; // 微秒
connectionTimes.add(duration);
}
} catch (Exception e) {
result.put("error", e.getMessage());
break;
}
try {
Thread.sleep(delayMs);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
// 分析结果
double avgTime = connectionTimes.stream()
.mapToLong(Long::longValue)
.average()
.orElse(0);
long maxTime = connectionTimes.stream()
.mapToLong(Long::longValue)
.max()
.orElse(0);
long minTime = connectionTimes.stream()
.mapToLong(Long::longValue)
.min()
.orElse(0);
result.put("success_count", connectionTimes.size());
result.put("avg_time_us", avgTime);
result.put("max_time_us", maxTime);
result.put("min_time_us", minTime);
result.put("pool_status", poolMonitor.collectHikariMetrics());
return ResponseEntity.ok(result);
}
/**
* Prometheus格式的监控指标
*/
@GetMapping("/metrics/prometheus")
public ResponseEntity<String> getPrometheusMetrics() {
StringBuilder sb = new StringBuilder();
PoolMetrics metrics = poolMonitor.collectHikariMetrics();
if (metrics != null) {
sb.append("# HELP pool_connection_active Active connections\n");
sb.append("# TYPE pool_connection_active gauge\n");
sb.append("pool_connection_active ").append(metrics.getActiveConnections()).append("\n");
sb.append("# HELP pool_connection_idle Idle connections\n");
sb.append("# TYPE pool_connection_idle gauge\n");
sb.append("pool_connection_idle ").append(metrics.getIdleConnections()).append("\n");
sb.append("# HELP pool_connection_usage_ratio Connection pool usage ratio\n");
sb.append("# TYPE pool_connection_usage_ratio gauge\n");
sb.append("pool_connection_usage_ratio ").append(metrics.getUsageRatio()).append("\n");
sb.append("# HELP pool_connection_waiting_threads Waiting threads\n");
sb.append("# TYPE pool_connection_waiting_threads gauge\n");
sb.append("pool_connection_waiting_threads ").append(metrics.getWaitingThreads()).append("\n");
}
return ResponseEntity.ok(sb.toString());
}
}
服务层
package com.example.monitor.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
@Service
public class DataSourceService {
@Autowired
private DataSource dataSource;
/**
* 测试数据库连接
*/
public boolean testConnection() {
try (Connection conn = dataSource.getConnection()) {
try (Statement stmt = conn.createStatement()) {
try (ResultSet rs = stmt.executeQuery("SELECT 1")) {
return rs.next() && rs.getInt(1) == 1;
}
}
} catch (Exception e) {
return false;
}
}
/**
* 获取数据库元数据
*/
public Map<String, Object> getDatabaseInfo() {
Map<String, Object> info = new HashMap<>();
try (Connection conn = dataSource.getConnection()) {
var metaData = conn.getMetaData();
info.put("url", metaData.getURL());
info.put("username", metaData.getUserName());
info.put("driverName", metaData.getDriverName());
info.put("driverVersion", metaData.getDriverVersion());
info.put("databaseProductName", metaData.getDatabaseProductName());
info.put("databaseProductVersion", metaData.getDatabaseProductVersion());
} catch (Exception e) {
info.put("error", e.getMessage());
}
return info;
}
}
配置文件
# application.yml
spring:
application:
name: db-pool-monitor
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4
username: root
password: password
# HikariCP配置
hikari:
pool-name: HikariPool-Main
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 300000
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
# Druid配置
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin123
web-stat-filter:
enabled: true
exclusions: "*.js,*.css,/druid/*"
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
logging:
level:
com.example.monitor: DEBUG
com.zaxxer.hikari: INFO
com.alibaba.druid: INFO
使用示例
package com.example.monitor.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/test")
public String testDB() {
// 模拟数据库操作
for (int i = 0; i < 10; i++) {
try (var conn = dataSource.getConnection()) {
try (var stmt = conn.createStatement()) {
try (var rs = stmt.executeQuery("SELECT NOW()")) {
if (rs.next()) {
System.out.println("Query result: " + rs.getString(1));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return "DB test completed";
}
}
监控效果展示
监控面板访问地址:
- HikariCP指标:
http://localhost:8080/api/monitor/metrics - Druid监控页面:
http://localhost:8080/druid/ - 健康检查:
http://localhost:8080/api/monitor/health - Prometheus指标:
http://localhost:8080/api/monitor/metrics/prometheus - 历史数据:
http://localhost:8080/api/monitor/history
配置告警规则(监控阈值):
- 连接池使用率 > 80%
- 等待线程数 > 10
- 连接获取超时
- 连接创建失败
这个案例提供了完整的数据库连接池监控解决方案,支持HikariCP和Druid两种主流连接池,包含实时监控、健康检查、告警和历史数据统计等功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播