全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-20 8 分钟 ✍️ juanwangdev

连接池调优

数据库连接池是 MyBatis 与数据库之间的桥梁。合理配置连接池参数可显著提升并发处理能力,避免连接耗尽、线程阻塞、资源浪费等问题。本文对比 HikariCP 与 Druid 的核心参数,给出生产环境的调优方案。

为什么需要连接池

每次创建数据库连接涉及:

  1. TCP 三次握手(网络延迟)
  2. 数据库认证(CPU 计算)
  3. 分配连接资源(内存)

单次建连耗时约 20ms ~ 50ms。连接池通过预创建、复用连接,将获取连接耗时降低至亚毫秒级。

HikariCP 连接池调优

HikariCP 是 Spring Boot 2.0+ 的默认连接池,以高性能、低延迟著称。

核心参数配置

YAML
spring:
  datasource:
    hikari:
      # 连接池最大连接数
      maximum-pool-size: 20
      # 最小空闲连接数
      minimum-idle: 5
      # 连接最大存活时间(毫秒),默认 30 分钟
      max-lifetime: 1800000
      # 连接超时时间(毫秒),默认 30 秒
      connection-timeout: 30000
      # 空闲连接超时时间(毫秒),默认 10 分钟
      idle-timeout: 600000
      # 连接测试查询
      connection-test-query: SELECT 1
      # 数据源名称(便于监控识别)
      pool-name: MyHikariPool

核心参数详解

参数含义推荐值说明
maximum-pool-size最大连接数CPU 核数 × 2 + 磁盘数并非越大越好,过多连接反而降低吞吐
minimum-idle最小空闲连接与 maximum-pool-size 相同或略低Hikari 官方建议不设置,让池自动管理
max-lifetime连接最大存活时间比数据库超时少 30 秒MySQL 默认 wait_timeout=28800(8小时),建议 25 ~ 30 分钟
connection-timeout获取连接超时30,000(30秒)超过此时间抛出 SQLTransientConnectionException
idle-timeout空闲连接回收超时600,000(10分钟)仅当 minimum-idle < maximum-pool-size 时生效

注意:HikariCP 官方作者建议 minimum-idle 不要设置,保持与 maximum-pool-size 相等,让连接池维持固定大小,避免频繁扩缩带来的性能抖动。

maximum-pool-size 计算公式

Java
最佳连接数 = CPU 核数 × 2 + 有效磁盘数

经验推导:

  • CPU 密集型操作(大量计算、复杂 SQL):连接数 ≈ CPU 核数
  • IO 密集型操作(简单查询、批量写入):连接数 ≈ CPU 核数 × 2 ~ 4
  • 混合场景:连接数 ≈ CPU 核数 × 2 + 磁盘数
CPU 核数IO 密集型推荐CPU 密集型推荐
48 ~ 124 ~ 6
816 ~ 248 ~ 12
1632 ~ 4816 ~ 24

注意:连接数超过数据库服务器的处理能力时,多余连接只会增加线程竞争和上下文切换开销。生产环境应结合压测数据确定最终值。

Java Config 方式

YAML
@Configuration
public class DataSourceConfig {

    @Bean
    @Primary
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC");
        config.setUsername("root");
        config.setPassword("password");
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(10);
        config.setMaxLifetime(1800000);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setConnectionTestQuery("SELECT 1");
        config.setPoolName("MyHikariPool");

        // 连接池监控
        config.setMetricRegistry(metricRegistry());

        return new HikariDataSource(config);
    }
}

Druid 连接池调优

Druid 是阿里巴巴开源的连接池,自带监控统计和 SQL 分析功能,在国内使用广泛。

核心参数配置

Java
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 初始连接数
      initial-size: 5
      # 最大活跃连接数
      max-active: 20
      # 最小空闲连接数
      min-idle: 5
      # 获取连接最大等待时间(毫秒)
      max-wait: 60000
      # 连接超时时间(毫秒)
      connect-timeout: 30000
      # Socket 超时(毫秒)
      socket-timeout: 60000
      # 空闲连接检测间隔(毫秒)
      time-between-eviction-runs-millis: 60000
      # 连接在池中最小生存时间(毫秒)
      min-evictable-idle-time-millis: 300000
      # 连接在池中最大生存时间(毫秒)
      max-evictable-idle-time-millis: 900000
      # 检测连接是否有效的 SQL
      validation-query: SELECT 1
      # 申请连接时执行 validation-query
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false

核心参数对比

参数HikariCPDruid说明
最大连接数maximum-pool-sizemax-active推荐值一致
最小空闲minimum-idlemin-idleHikari 建议不设置,Druid 可设置
获取超时connection-timeoutmax-wait建议 30 秒
连接存活时间max-lifetimemax-evictable-idle-time-millis建议 25 ~ 30 分钟
空闲超时idle-timeoutmin-evictable-idle-time-millis建议 10 分钟
有效性检测connection-test-queryvalidation-queryHikari 默认自动检测,Druid 需手动指定

Druid 监控配置

Druid 的优势之一是内置监控页面和 SQL 分析:

YAML
@Configuration
public class DruidConfig {

    @Bean
    public ServletRegistrationBean<StatViewServlet> statViewServlet() {
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>();
        bean.setServlet(new StatViewServlet());
        bean.addUrlMappings("/druid/*");
        bean.addInitParameter("loginUsername", "admin");
        bean.addInitParameter("loginPassword", "admin123");
        bean.addInitParameter("resetEnable", "false");
        return bean;
    }

    @Bean
    public FilterRegistrationBean<WebStatFilter> webStatFilter() {
        FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new WebStatFilter());
        bean.addUrlPatterns("/*");
        bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");
        return bean;
    }
}

Druid SQL 防火墙

YAML
spring:
  datasource:
    druid:
      filter:
        stat:
          slow-sql-millis: 2000  # 超过 2 秒记录为慢 SQL
          log-slow-sql: true     # 打印慢 SQL 日志
        wall:
          enabled: true          # 开启 SQL 防火墙
          config:
            delete-allow: false  # 禁止 DELETE 无 WHERE 条件
            drop-table-allow: false  # 禁止 DROP TABLE

连接泄漏检测

HikariCP 泄漏检测

YAML
spring:
  datasource:
    hikari:
      leak-detection-threshold: 60000  # 超过 60 秒未归还连接则告警
Java
WARN  com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detected:
  Connection leased for 60,012ms. Threshold: 60,000ms
  at com.example.service.UserService.getUser(UserService.java:42)

注意:leak-detection-threshold 仅用于开发/测试环境,生产环境不建议开启,因为它会对未超时连接也产生额外开销。

Druid 泄漏检测

SQL
spring:
  datasource:
    druid:
      remove-abandoned: true           # 开启泄漏检测
      remove-abandoned-timeout: 180    # 超过 180 秒未归还则回收
      log-abandoned: true              # 打印泄漏堆栈

常见连接池问题排查

连接耗尽

现象:应用响应缓慢,日志出现 Connection is not available, request timed out

排查步骤:

  1. 检查 maximum-pool-size 是否过小
  2. 检查是否存在未关闭的 SqlSession / Connection
  3. 检查是否存在慢查询长时间占用连接
  4. 监控连接池活跃连接数与等待线程数
YAML
// 正确:使用 try-with-resources 确保 Session 关闭
try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    return mapper.selectById(id);
}
// session 自动关闭,连接自动归还到池

连接频繁重建

现象:连接池日志频繁出现 Connection created / Connection closed

原因:max-lifetime 设置过短,或数据库侧 wait_timeout 小于连接池配置,导致连接被数据库强制关闭。

解决:确保 max-lifetime 比数据库 wait_timeout 少至少 30 秒。

XML
-- 查看 MySQL wait_timeout
SHOW VARIABLES LIKE 'wait_timeout';
-- 输出:28800(8小时)

-- 推荐连接池 max-lifetime < wait_timeout - 30秒
-- 建议:25 ~ 30 分钟即可,无需匹配数据库 8 小时

空闲连接被防火墙回收

现象:连接池中的连接长时间不使用,被中间防火墙/NAT 设备强制断开,使用时报错。

解决:设置合理的 idle-timeout 和心跳检测:

Java
spring:
  datasource:
    hikari:
      idle-timeout: 300000     # 5 分钟空闲即回收
      keepalive-time: 30000    # 每 30 秒发送心跳保活
      max-lifetime: 1800000    # 30 分钟强制重建

MyBatis 与连接池集成

MyBatis 原生配置(不推荐,Spring 环境下由 Spring 管理)

text
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
            <property name="username" value="root"/>
            <property name="password" value="password"/>
            <property name="poolMaximumActiveConnections" value="20"/>
            <property name="poolMaximumIdleConnections" value="5"/>
            <property name="poolMaximumCheckoutTime" value="20000"/>
            <property name="poolTimeToWait" value="20000"/>
        </dataSource>
    </environment>
</environments>

Spring Boot 集成(推荐)

text
@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);

        // MyBatis 自身配置
        org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
        config.setMapUnderscoreToCamelCase(true);
        config.setCacheEnabled(true);
        config.setLazyLoadingEnabled(true);
        factoryBean.setConfiguration(config);

        return factoryBean.getObject();
    }
}

要点总结

  • HikariCP 性能优于 Druid,是 Spring Boot 默认连接池;Druid 优势在于监控和 SQL 分析
  • maximum-pool-size 推荐值 = CPU 核数 × 2 + 磁盘数,并非越大越好
  • max-lifetime 应比数据库 wait_timeout 少 30 秒以上,推荐 25 ~ 30 分钟
  • HikariCP 官方建议不设置 minimum-idle,保持固定池大小
  • 开启泄漏检测用于开发环境排查,生产环境不建议开启
  • 正确关闭 SqlSession 避免连接泄漏,推荐使用 try-with-resources
  • 防火墙/NAT 环境下设置 keepalive-time 保活连接
  • Druid 可配置 SQL 防火墙和慢 SQL 日志,适合安全审计场景

📝 发现内容有误?点击此处直接编辑

← 上一篇 缓存策略优化
下一篇 → SQL 审计日志插件
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库