浅析HikariCP配置与集成

浅析HikariCP配置与集成

HikariCP 是一个高性能的 JDBC 连接池组件,号称性能最好的后起之秀,是一个基于BoneCP做了不少的改进和优化的高性能JDBC连接池。本文将从配置和SpringBoot集成进行分析

1. HikariCP配置

1.1 HikariConfig

HikariConfig的成员变量涵盖了所有Hikari连接池的配置,如下:

java 复制代码
//运行时,可以修改的配置。

//从连接池获取连接的超时时间,默认30s
private volatile long connectionTimeout;
//检验连接是否有效的超时时间,默认5s
private volatile long validationTimeout;
//连接空闲时间,当最小连接数 < 最大连接数生效。默认10min
private volatile long idleTimeout;
//连接泄漏检测时长,默认0不开启,最大值不能超过maxLifetime
private volatile long leakDetectionThreshold;
//连接最大存活时间,默认30min。需要小于数据库wait_timeout,超过这个时间未使用连接都会关闭。
private volatile long maxLifetime;
//最大连接数,默认10
private volatile int maxPoolSize;
//最小连接数,默认10
private volatile int minIdle;


//运行时,无法修改的配置

//初始化检测与数据库连接是否ok的超时时间,默认1ms,为0代表不做初始化检查。
private long initializationFailTimeout;
//创建连接成功后,在放入连接池之前,执行的sql
private String connectionInitSql;
//检测连接是否可用的sql,如果为空使用ping,否则使用这个sql
private String connectionTestQuery;
//是否自动提交,默认true
private Boolean isAutoCommit;
//是否只读,默认false
private Boolean isReadOnly;
//是否注册MBean
private Boolean isRegisterMbeans;
//是否允许连接池挂起,默认否
private Boolean isAllowPoolSuspension;

1.2 参数检验

检验方法在HikariConfig中的validateNumerics方法。

1)如果maxLifetime小于30s,则会用默认的时长:30min

java 复制代码
if (maxLifetime != 0 && maxLifetime < SECONDS.toMillis(30)) {
	LOGGER.warn("{} - maxLifetime is less than 30000ms, setting to default {}ms.", poolName, MAX_LIFETIME);
	maxLifetime = MAX_LIFETIME;
}

2)如果maxLifetime大于0,idleTimeout + 1s 大于maxLifetime,则idleTimeout设置为0,表示不生效

java 复制代码
if (idleTimeout + SECONDS.toMillis(1) > maxLifetime && maxLifetime > 0) {
	LOGGER.warn("{} - idleTimeout is close to or more than maxLifetime, disabling it.", poolName);
	idleTimeout = 0;
}

3)如果idleTimeout大于0,且小于10s,则设置成默认时长:10min

java 复制代码
if (idleTimeout != 0 && idleTimeout < SECONDS.toMillis(10)) {
	LOGGER.warn("{} - idleTimeout is less than 10000ms, setting to default {}ms.", poolName, IDLE_TIMEOUT);
	idleTimeout = IDLE_TIMEOUT;
}

4)如果获取连接超时时长小于250ms,则设置为默认超时时长:30s

java 复制代码
if (connectionTimeout < 250) {
	LOGGER.warn("{} - connectionTimeout is less than 250ms, setting to {}ms.", poolName, CONNECTION_TIMEOUT);
	connectionTimeout = CONNECTION_TIMEOUT;
}

5)如果验证时长小于250ms,则设置为默认验证超时时长:5s

java 复制代码
if (validationTimeout < 250) {
	LOGGER.warn("{} - validationTimeout is less than 250ms, setting to {}ms.", poolName, VALIDATION_TIMEOUT);
	validationTimeout = VALIDATION_TIMEOUT;
}

6)如果最大连接数小于1,如果最小连接数没设置,则设置成默认10,否则设置成最小连接数。

java 复制代码
if (maxPoolSize < 1) {
	maxPoolSize = (minIdle <= 0) ? DEFAULT_POOL_SIZE : minIdle;
}

7)如果最小连接数设置,且大于最大连接数,则设置为最大连接数

java 复制代码
if (minIdle < 0 || minIdle > maxPoolSize) {
	minIdle = maxPoolSize;
}

1.3 参数用途

  • validationTimeout:用于Connection接口的setNetworkTimeout方法,底层与应该是设置SocketTimeout的时长。另外如果设置连接查询参数,会调用Connection的isValid的接口,参数都是用validationTimeout,且最小不会少于1s。
java 复制代码
//PoolBase#isConnectionAlive
setNetworkTimeout(connection, validationTimeout);
final int validationSeconds = (int) Math.max(1000L, validationTimeout) / 1000;
if (isUseJdbc4Validation) {
	return connection.isValid(validationSeconds);
}
  • connectionTimeout:1)会被设置成DataSource的setLoginTimeout的参数。2)HikariPool对象池中获取对象的超时时长。

  • idleTimeout:如果对象处理空闲(并且要大于minimumIdle的数量),就会把连接给关闭掉。注意:即使设置了该参数,连接池对象也不会少于minimumIdle的数量。

  • maxLifeTime:连接最长存活的时间,不论对象是处于什么状态。在创建连接对象时,通过延迟任务处理。

  • minimumIdle:最少空闲连接数。空闲的连接有一定可用的数量,会在很多地方进行填充。

  • maxPoolSize:连接池最大对象数量。包括所有状态。

2. Spring Boot集成

2.1 数据源是什么

数据源(DataSource是用于连接物理的数据来源(如数据库),用于替代JDBC的DriverManager,使用URL和凭据(credentials)来建立数据库连接。

数据源可用于获取:

  • 标准connection对象。
  • 可被连接池管理的连接。
  • 可被分布式、支持事务的连接池管理的连接。

2.2 框架如何使用数据源

  • 以Mybatis为例。在MybatisAutoConfiguration中,会自动创建一个SqlSessionFactory,其中创建该方法直接依赖了DataSource 数据源
java 复制代码
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    //....
    return factory.getObject();
}

2.3 Spring Boot 如何集成

  • 在DataSourceAutoConfiguration中,默认会按顺序加载Hikari、Tomcat、Dbcp2(只会加载一个)。
java 复制代码
@Bean
@ConfigurationProperties(
    prefix = "spring.datasource.hikari"
)
    public HikariDataSource dataSource(DataSourceProperties properties) {
        HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
        if (StringUtils.hasText(properties.getName())) {
            dataSource.setPoolName(properties.getName());
        }

        return dataSource;
    }

也可以在业务中显示的创建DataSource

java 复制代码
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().type(HikariDataSource.class).build();
}

HikariDataSource继承了HikariConfig实现了DataSource接口,所以@ConfigurationProperties会把配置直接注入进去。

使用DataSource的入口是从getConnection()获取一个连接开始。

该方法会判断一个连接池对象是否创建,如果没有创建则进行初始化。是一个典型的懒加载单例模式,pool对象用volatile关键字修饰。

java 复制代码
public Connection getConnection() throws SQLException
{  
   //...
   HikariPool result = pool;
   if (result == null) {
      synchronized (this) {
         result = pool;
         if (result == null) {
            validate();
            LOGGER.info("{} - Starting...", getPoolName());
            try {
               pool = result = new HikariPool(this);
               this.seal();
            }catch (PoolInitializationException pie) {
               //...
            }
            LOGGER.info("{} - Start completed.", getPoolName());
         }
      }
   }
   return result.getConnection();
}

3. 参考资料

相关推荐
颜淡慕潇9 分钟前
【K8S问题系列 |19 】如何解决 Pod 无法挂载 PVC问题
后端·云原生·容器·kubernetes
ProtonBase16 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v22 分钟前
leetCode43.字符串相乘
java·数据结构·算法
suweijie7684 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿4 小时前
List深拷贝后,数据还是被串改
java
向前看-7 小时前
验证码机制
前端·后端
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹8 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭9 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫9 小时前
泛型(2)
java