数据库连接池性能优化深度解析:HikariCP vs Druid调优实战及监控告警配置

PoorXena
PoorXena 2026-01-18T16:11:16+08:00
0 0 1

引言

在现代企业级应用开发中,数据库连接池作为连接数据库的核心组件,其性能直接影响到整个系统的响应速度和稳定性。随着业务规模的不断扩大,如何选择合适的连接池实现、如何进行有效的参数调优以及如何建立完善的监控告警体系,成为了每个后端开发者必须面对的重要课题。

本文将深入分析主流数据库连接池HikariCP和Druid的性能特点,提供详细的调优参数配置指南。通过实际业务场景的模拟,我们将介绍连接池监控指标设置、性能瓶颈诊断方法和告警策略制定,确保数据库访问的高效稳定。

一、数据库连接池概述与选择

1.1 数据库连接池的作用

数据库连接池是一种用于管理数据库连接的缓存机制。它通过预先创建一定数量的数据库连接,并将这些连接存储在池中,当应用程序需要访问数据库时,直接从池中获取连接,使用完毕后再归还到池中,从而避免了频繁创建和销毁连接所带来的性能开销。

1.2 HikariCP与Druid对比分析

HikariCP特点

HikariCP是目前性能最好的数据库连接池之一,其主要优势包括:

  • 高性能:基于字节码优化,性能比传统连接池提升数倍
  • 轻量级:代码简洁,内存占用少
  • 自动配置:提供合理的默认参数配置
  • 监控支持:内置JMX监控接口

Druid特点

Druid是阿里巴巴开源的数据库连接池,具有以下特色:

  • 功能丰富:提供SQL监控、慢SQL记录等功能
  • 可扩展性强:支持多种插件机制
  • 监控全面:内置Web管理界面
  • 兼容性好:对各种数据库支持良好

二、HikariCP性能优化实战

2.1 基础配置参数详解

# HikariCP配置示例
spring:
  datasource:
    hikari:
      # 连接池名称
      pool-name: MyHikariPool
      # 最小空闲连接数
      minimum-idle: 10
      # 最大连接数
      maximum-pool-size: 50
      # 连接超时时间
      connection-timeout: 30000
      # 空闲连接超时时间
      idle-timeout: 600000
      # 连接生命周期
      max-lifetime: 1800000
      # 连接测试查询
      connection-test-query: SELECT 1
      # 自动提交
      auto-commit: true
      # 连接池验证
      validation-timeout: 5000

2.2 核心调优参数说明

连接池大小优化

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        // 根据业务并发量设置
        config.setMaximumPoolSize(50);
        config.setMinimumIdle(10);
        
        // 预估并发请求数量
        int concurrentRequests = 200;
        // 建议最大连接数 = 并发数 + 10%缓冲
        int maxPoolSize = (int) (concurrentRequests * 1.1);
        config.setMaximumPoolSize(maxPoolSize);
        
        return new HikariDataSource(config);
    }
}

连接超时设置优化

// 根据网络环境和数据库响应时间调整
HikariConfig config = new HikariConfig();
config.setConnectionTimeout(30000);      // 30秒
config.setIdleTimeout(600000);          // 10分钟
config.setMaxLifetime(1800000);          // 30分钟
config.setValidationTimeout(5000);      // 5秒

2.3 性能测试与调优

@Component
public class ConnectionPoolBenchmark {
    
    private static final Logger logger = LoggerFactory.getLogger(ConnectionPoolBenchmark.class);
    
    public void performanceTest() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        config.setUsername("user");
        config.setPassword("password");
        
        // 不同配置下的性能测试
        testConfiguration(config, 10, "小连接池");
        testConfiguration(config, 50, "中等连接池");
        testConfiguration(config, 100, "大连接池");
    }
    
    private void testConfiguration(HikariConfig config, int poolSize, String description) {
        config.setMaximumPoolSize(poolSize);
        HikariDataSource dataSource = new HikariDataSource(config);
        
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            try (Connection conn = dataSource.getConnection()) {
                // 模拟数据库操作
                PreparedStatement ps = conn.prepareStatement("SELECT 1");
                ps.executeQuery();
            } catch (SQLException e) {
                logger.error("Database connection failed", e);
            }
        }
        long endTime = System.currentTimeMillis();
        
        logger.info("{} - 耗时: {}ms, 连接池大小: {}", 
                   description, (endTime - startTime), poolSize);
        
        dataSource.close();
    }
}

三、Druid连接池调优实践

3.1 Druid核心配置参数

# Druid配置示例
spring:
  datasource:
    druid:
      # 基础配置
      url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false
      username: root
      password: password
      driver-class-name: com.mysql.cj.jdbc.Driver
      
      # 连接池配置
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      
      # 监控配置
      filters: stat,wall,log4j
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        login-username: admin
        login-password: admin
        reset-enable: false

3.2 Druid监控配置

@Configuration
public class DruidConfig {
    
    @Bean
    public ServletRegistrationBean<StatViewServlet> statViewServlet() {
        StatViewServlet servlet = new StatViewServlet();
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(servlet);
        
        bean.setUrlMappings("/druid/*");
        bean.setInitParameters(new HashMap<String, String>() {{
            put("loginUsername", "admin");
            put("loginPassword", "admin");
            put("resetEnable", "false");
            put("allow", "");
        }});
        
        return bean;
    }
    
    @Bean
    public FilterRegistrationBean<WebStatFilter> webStatFilter() {
        WebStatFilter filter = new WebStatFilter();
        FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>(filter);
        
        bean.setUrlPatterns("/*");
        bean.setInitParameters(new HashMap<String, String>() {{
            put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        }});
        
        return bean;
    }
}

3.3 Druid SQL监控分析

@Component
public class SqlMonitorService {
    
    private static final Logger logger = LoggerFactory.getLogger(SqlMonitorService.class);
    
    public void analyzeSlowSql() {
        // 获取慢SQL统计信息
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = null;
        try {
            name = new ObjectName("com.alibaba.druid:type=Stat");
            ObjectAttributeInfo[] attributes = server.getAttributes(name, new String[]{"SlowSQLList"}).toArray();
            
            for (ObjectAttributeInfo attr : attributes) {
                logger.info("Slow SQL: {}", attr.getValue());
            }
        } catch (Exception e) {
            logger.error("Error getting slow SQL statistics", e);
        }
    }
    
    public void monitorConnectionPool() {
        // 监控连接池状态
        DruidDataSource dataSource = (DruidDataSource) getDataSource();
        
        logger.info("Active connections: {}", dataSource.getActiveCount());
        logger.info("Idle connections: {}", dataSource.getIdleCount());
        logger.info("Total connections: {}", dataSource.getCreateCount());
        logger.info("Connection wait time: {}ms", dataSource.getWaitTimeMillis());
    }
}

四、连接池监控指标体系

4.1 核心监控指标

@Component
public class ConnectionPoolMetrics {
    
    private static final Logger logger = LoggerFactory.getLogger(ConnectionPoolMetrics.class);
    
    // 连接池状态指标
    public void collectMetrics() {
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        
        // 基础指标收集
        HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
        
        logger.info("Active connections: {}", poolBean.getActiveConnections());
        logger.info("Idle connections: {}", poolBean.getIdleConnections());
        logger.info("Total connections: {}", poolBean.getTotalConnections());
        logger.info("Threads waiting: {}", poolBean.getThreadsAwaitingConnection());
        logger.info("Connection timeout count: {}", poolBean.getConnectionTimeoutCount());
        
        // 性能指标
        logger.info("Average wait time: {}ms", poolBean.getAverageIdleTime());
        logger.info("Average active time: {}ms", poolBean.getAverageLifetime());
    }
    
    // 自定义指标监控
    public void customMonitoring() {
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        
        // 记录连接获取时间
        long startTime = System.currentTimeMillis();
        try (Connection conn = dataSource.getConnection()) {
            long endTime = System.currentTimeMillis();
            logger.info("Connection acquisition time: {}ms", (endTime - startTime));
        } catch (SQLException e) {
            logger.error("Failed to get connection", e);
        }
    }
}

4.2 Prometheus监控集成

@Component
public class PrometheusMetricsCollector {
    
    private static final Gauge activeConnections;
    private static final Gauge idleConnections;
    private static final Gauge totalConnections;
    private static final Counter connectionTimeouts;
    
    static {
        activeConnections = Gauge.build()
            .name("db_pool_active_connections")
            .help("Active database connections")
            .register();
            
        idleConnections = Gauge.build()
            .name("db_pool_idle_connections")
            .help("Idle database connections")
            .register();
            
        totalConnections = Gauge.build()
            .name("db_pool_total_connections")
            .help("Total database connections")
            .register();
            
        connectionTimeouts = Counter.build()
            .name("db_pool_connection_timeouts_total")
            .help("Database connection timeouts")
            .register();
    }
    
    public void updateMetrics(HikariDataSource dataSource) {
        HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
        
        activeConnections.set(poolBean.getActiveConnections());
        idleConnections.set(poolBean.getIdleConnections());
        totalConnections.set(poolBean.getTotalConnections());
        connectionTimeouts.inc(poolBean.getConnectionTimeoutCount());
    }
}

五、性能瓶颈诊断方法

5.1 连接池瓶颈识别

@Component
public class PoolBottleneckDetector {
    
    private static final Logger logger = LoggerFactory.getLogger(PoolBottleneckDetector.class);
    
    public void detectBottlenecks() {
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
        
        // 检查连接等待情况
        int threadsAwaiting = poolBean.getThreadsAwaitingConnection();
        if (threadsAwaiting > 0) {
            logger.warn("Connection pool bottleneck detected: {} threads waiting", threadsAwaiting);
            analyzeWaitingThreads();
        }
        
        // 检查超时情况
        long timeouts = poolBean.getConnectionTimeoutCount();
        if (timeouts > 0) {
            logger.warn("Connection timeouts occurred: {}", timeouts);
            diagnoseTimeouts();
        }
    }
    
    private void analyzeWaitingThreads() {
        // 分析等待线程的堆栈信息
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadBean.dumpAllThreads(false, false);
        
        for (ThreadInfo threadInfo : threadInfos) {
            if (threadInfo.getStackTrace().length > 0) {
                // 找到等待数据库连接的线程
                for (StackTraceElement element : threadInfo.getStackTrace()) {
                    if (element.getClassName().contains("HikariPool")) {
                        logger.info("Waiting thread: {} - {}", 
                                  threadInfo.getThreadName(), element);
                    }
                }
            }
        }
    }
    
    private void diagnoseTimeouts() {
        // 分析超时原因
        try {
            // 检查数据库连接状态
            Connection conn = getDataSource().getConnection();
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SHOW PROCESSLIST");
            
            while (rs.next()) {
                logger.info("Process: {} - {}", rs.getInt("Id"), rs.getString("Info"));
            }
            
            conn.close();
        } catch (SQLException e) {
            logger.error("Failed to diagnose timeouts", e);
        }
    }
}

5.2 内存使用监控

@Component
public class MemoryUsageMonitor {
    
    private static final Logger logger = LoggerFactory.getLogger(MemoryUsageMonitor.class);
    
    public void monitorMemoryUsage() {
        // 获取JVM内存信息
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
        
        long used = heapUsage.getUsed();
        long max = heapUsage.getMax();
        double usagePercent = (double) used / max * 100;
        
        logger.info("JVM Heap Usage: {}MB / {}MB ({:.2f}%)", 
                   used / (1024 * 1024), 
                   max / (1024 * 1024), 
                   usagePercent);
        
        // 检查连接池内存占用
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
        
        logger.info("Connection Pool Info:");
        logger.info("  Active connections: {}", poolBean.getActiveConnections());
        logger.info("  Idle connections: {}", poolBean.getIdleConnections());
        logger.info("  Total connections: {}", poolBean.getTotalConnections());
    }
    
    public void detectMemoryLeak() {
        // 检测潜在的内存泄漏
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
        
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            long collectionCount = gcBean.getCollectionCount();
            long collectionTime = gcBean.getCollectionTime();
            
            logger.info("GC {}: {} collections, {}ms", 
                       gcBean.getName(), collectionCount, collectionTime);
        }
    }
}

六、告警策略制定与实现

6.1 告警指标配置

@Component
public class AlertingService {
    
    private static final Logger logger = LoggerFactory.getLogger(AlertingService.class);
    
    // 连接池告警阈值
    private static final double HIGH_CONNECTION_USAGE_THRESHOLD = 0.8;
    private static final int HIGH_WAITING_THREADS_THRESHOLD = 5;
    private static final long HIGH_TIMEOUTS_THRESHOLD = 10;
    
    public void checkAlerts() {
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
        
        // 检查连接使用率
        int activeConnections = poolBean.getActiveConnections();
        int totalConnections = poolBean.getTotalConnections();
        double usageRate = (double) activeConnections / totalConnections;
        
        if (usageRate > HIGH_CONNECTION_USAGE_THRESHOLD) {
            sendAlert("High Connection Pool Usage", 
                     String.format("Usage rate: %.2f%%", usageRate * 100));
        }
        
        // 检查等待线程数
        int waitingThreads = poolBean.getThreadsAwaitingConnection();
        if (waitingThreads > HIGH_WAITING_THREADS_THRESHOLD) {
            sendAlert("High Waiting Threads", 
                     String.format("Waiting threads: %d", waitingThreads));
        }
        
        // 检查超时次数
        long timeouts = poolBean.getConnectionTimeoutCount();
        if (timeouts > HIGH_TIMEOUTS_THRESHOLD) {
            sendAlert("High Connection Timeouts", 
                     String.format("Timeouts count: %d", timeouts));
        }
    }
    
    private void sendAlert(String title, String message) {
        logger.error("ALERT - {}: {}", title, message);
        
        // 可以集成邮件、短信、微信等告警方式
        // 这里简化为日志记录
        AlertEvent event = new AlertEvent();
        event.setTitle(title);
        event.setMessage(message);
        event.setTimestamp(System.currentTimeMillis());
        
        // 发送告警通知
        notifyAlert(event);
    }
    
    private void notifyAlert(AlertEvent event) {
        // 告警通知实现
        logger.info("Sending alert notification: {}", event);
    }
}

6.2 告警处理机制

@Component
public class AlertHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(AlertHandler.class);
    
    @EventListener
    public void handleAlert(AlertEvent event) {
        logger.info("Handling alert: {}", event.getTitle());
        
        // 根据告警类型执行不同的处理逻辑
        switch (event.getTitle()) {
            case "High Connection Pool Usage":
                handleHighUsage(event);
                break;
            case "High Waiting Threads":
                handleHighWaiting(event);
                break;
            case "High Connection Timeouts":
                handleTimeouts(event);
                break;
            default:
                logger.warn("Unknown alert type: {}", event.getTitle());
        }
    }
    
    private void handleHighUsage(AlertEvent event) {
        // 增加连接池大小
        logger.info("Increasing connection pool size...");
        increasePoolSize();
        
        // 记录处理日志
        logAction("Increased pool size due to high usage");
    }
    
    private void handleHighWaiting(AlertEvent event) {
        // 检查数据库性能
        logger.info("Checking database performance...");
        analyzeDatabasePerformance();
        
        // 可能需要优化SQL或增加资源
        logAction("Investigating high waiting threads");
    }
    
    private void handleTimeouts(AlertEvent event) {
        // 重置连接池
        logger.info("Resetting connection pool...");
        resetConnectionPool();
        
        // 检查数据库连接状态
        checkDatabaseStatus();
    }
    
    private void increasePoolSize() {
        // 实现动态调整连接池大小的逻辑
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        int currentMax = dataSource.getHikariConfig().getMaximumPoolSize();
        dataSource.setConnectionTimeout(currentMax + 10);
    }
    
    private void resetConnectionPool() {
        // 重置连接池的逻辑
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        dataSource.close();
        
        // 重新初始化
        initializeDataSource();
    }
    
    private void logAction(String action) {
        logger.info("Alert handler action: {}", action);
    }
}

七、实际业务场景调优案例

7.1 电商系统调优实践

@Service
public class EcommerceService {
    
    @Autowired
    private DataSource dataSource;
    
    // 针对高并发场景的连接池配置
    @PostConstruct
    public void configureForEcommerce() {
        if (dataSource instanceof HikariDataSource) {
            HikariDataSource hikariDS = (HikariDataSource) dataSource;
            
            // 电商系统通常需要处理大量并发请求
            hikariDS.setMaximumPoolSize(100);
            hikariDS.setMinimumIdle(20);
            hikariDS.setConnectionTimeout(30000);
            hikariDS.setIdleTimeout(600000);
            hikariDS.setMaxLifetime(1800000);
            
            // 针对电商场景的特殊优化
            hikariDS.setLeakDetectionThreshold(60000);
            hikariDS.setConnectionTestQuery("SELECT 1");
        }
    }
    
    @Transactional
    public void processOrder(Order order) {
        // 模拟订单处理流程
        try (Connection conn = dataSource.getConnection()) {
            // 订单创建逻辑
            PreparedStatement ps1 = conn.prepareStatement(
                "INSERT INTO orders (user_id, amount, status) VALUES (?, ?, ?)");
            ps1.setLong(1, order.getUserId());
            ps1.setBigDecimal(2, order.getAmount());
            ps1.setString(3, "PENDING");
            ps1.executeUpdate();
            
            // 库存扣减
            PreparedStatement ps2 = conn.prepareStatement(
                "UPDATE inventory SET quantity = quantity - ? WHERE product_id = ?");
            ps2.setInt(1, order.getQuantity());
            ps2.setLong(2, order.getProductId());
            ps2.executeUpdate();
            
        } catch (SQLException e) {
            throw new RuntimeException("Order processing failed", e);
        }
    }
}

7.2 高频查询场景优化

@Component
public class HighFrequencyQueryService {
    
    private static final Logger logger = LoggerFactory.getLogger(HighFrequencyQueryService.class);
    
    @Autowired
    private DataSource dataSource;
    
    // 针对高频查询的连接池优化
    public List<Product> getProductsByCategory(long categoryId, int limit) {
        HikariDataSource hikariDS = (HikariDataSource) dataSource;
        
        // 为高频查询设置更优的配置
        long startTime = System.currentTimeMillis();
        try (Connection conn = dataSource.getConnection()) {
            PreparedStatement ps = conn.prepareStatement(
                "SELECT * FROM products WHERE category_id = ? ORDER BY created_time DESC LIMIT ?");
            ps.setLong(1, categoryId);
            ps.setInt(2, limit);
            
            ResultSet rs = ps.executeQuery();
            List<Product> products = new ArrayList<>();
            
            while (rs.next()) {
                Product product = new Product();
                product.setId(rs.getLong("id"));
                product.setName(rs.getString("name"));
                product.setPrice(rs.getBigDecimal("price"));
                product.setCategory(rs.getLong("category_id"));
                products.add(product);
            }
            
            return products;
        } catch (SQLException e) {
            logger.error("Failed to get products by category", e);
            throw new RuntimeException("Database query failed", e);
        } finally {
            long endTime = System.currentTimeMillis();
            logger.info("Product query took {}ms", (endTime - startTime));
        }
    }
    
    // 监控高频查询性能
    @Scheduled(fixedRate = 30000)
    public void monitorQueryPerformance() {
        HikariDataSource hikariDS = (HikariDataSource) dataSource;
        HikariPoolMXBean poolBean = hikariDS.getHikariPoolMXBean();
        
        logger.info("Query Performance Metrics:");
        logger.info("  Active connections: {}", poolBean.getActiveConnections());
        logger.info("  Idle connections: {}", poolBean.getIdleConnections());
        logger.info("  Threads waiting: {}", poolBean.getThreadsAwaitingConnection());
    }
}

八、最佳实践总结

8.1 连接池配置建议

@Configuration
public class BestPracticesConfig {
    
    /**
     * 推荐的连接池配置原则
     */
    public static HikariConfig getRecommendedConfig() {
        HikariConfig config = new HikariConfig();
        
        // 1. 合理设置连接池大小
        // 基于业务并发量和数据库处理能力
        config.setMaximumPoolSize(50);
        config.setMinimumIdle(10);
        
        // 2. 设置合理的超时时间
        config.setConnectionTimeout(30000);    // 30秒
        config.setIdleTimeout(600000);         // 10分钟
        config.setMaxLifetime(1800000);         // 30分钟
        
        // 3. 启用连接验证
        config.setConnectionTestQuery("SELECT 1");
        config.setValidationTimeout(5000);     // 5秒
        
        // 4. 开启泄漏检测
        config.setLeakDetectionThreshold(60000); // 1分钟
        
        return config;
    }
    
    /**
     * 根据环境动态调整配置
     */
    public HikariConfig getEnvironmentSpecificConfig(String environment) {
        HikariConfig config = getRecommendedConfig();
        
        switch (environment.toLowerCase()) {
            case "development":
                // 开发环境:较小的连接池
                config.setMaximumPoolSize(10);
                config.setMinimumIdle(5);
                break;
            case "staging":
                // 预发布环境:中等连接池
                config.setMaximumPoolSize(30);
                config.setMinimumIdle(10);
                break;
            case "production":
                // 生产环境:较大的连接池
                config.setMaximumPoolSize(100);
                config.setMinimumIdle(20);
                break;
            default:
                // 默认配置
                break;
        }
        
        return config;
    }
}

8.2 性能监控最佳实践

@Component
public class MonitoringBestPractices {
    
    private static final Logger logger = LoggerFactory.getLogger(MonitoringBestPractices.class);
    
    /**
     * 定期收集和分析监控数据
     */
    @Scheduled(fixedRate = 60000) // 每分钟执行一次
    public void collectPerformanceData() {
        try {
            // 收集核心指标
            collectCoreMetrics();
            
            // 分析趋势
            analyzeTrends();
            
            // 发现异常
            detectAnomalies();
            
        } catch (Exception e) {
            logger.error("Failed to collect performance data", e);
        }
    }
    
    private void collectCoreMetrics() {
        HikariDataSource dataSource = (HikariDataSource) getDataSource();
        HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
        
        // 记录关键指标
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("active_connections", poolBean.getActiveConnections());
        metrics.put("idle_connections", poolBean.getIdleConnections());
        metrics.put("total_connections", poolBean.getTotalConnections());
        metrics.put("threads_awaiting", poolBean.getThreadsAwaitingConnection());
        metrics.put("timeout_count", poolBean.getConnectionTimeoutCount());
        
        //
相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000