Hikari连接的创建过程

HouseKeeper 和 HikariPool#addBagItem 在需要新增db连接的时候,都是往负责连接创建的线程池 addConnectionExecutorPoolEntryCreator implements Callable<Boolean> 任务

PoolEntryCreator#call()

public Boolean call(){
    long sleepBackoff = 250L;
		**// 1.** 判断是否需要创建
    while (poolState == POOL_NORMAL && **shouldCreateAnotherConnection()**) {
      **// 2.** 创建db连接条目
      final PoolEntry poolEntry = createPoolEntry();
      if (poolEntry != null) {
         connectionBag.add(poolEntry);
         logger.debug("{} - Added connection {}", poolName, poolEntry.connection);
         if (loggingPrefix != null) {
            logPoolState(loggingPrefix);
         }
         return Boolean.TRUE;
      }
			
			**// 3.** 休眠后重试
      // failed to get connection from db, sleep and retry
      if (loggingPrefix != null) logger.debug("{} - Connection add failed, sleeping with backoff: {}ms", poolName, sleepBackoff);
      quietlySleep(sleepBackoff);
      sleepBackoff = Math.min(SECONDS.toMillis(10), Math.min(connectionTimeout, (long) (sleepBackoff * 1.5)));
   }

   // Pool is suspended or shutdown or at max size
	return Boolean.FALSE;
}

1. while (poolState == POOL_NORMAL && shouldCreateAnotherConnection()) { .. } 判断是否需要创建

private synchronized boolean shouldCreateAnotherConnection() {
         return getTotalConnections() < config.getMaximumPoolSize() &&
            (connectionBag.getWaitingThreadCount() > 0 || getIdleConnections() < config.getMinimumIdle());
}

当前总的连接数小于 maximumPoolSize 最大连接数的前提下,如果有线程等待 db连接 或 池内空闲线程数小于最小空闲线程数 才会去创建新db连接

2. final PoolEntry poolEntry = createPoolEntry(); 创建db连接条目,成功的话添加到池子 connectionBag 里

private PoolEntry createPoolEntry()
   {
      try {
         final PoolEntry poolEntry = newPoolEntry();

         final long maxLifetime = config.getMaxLifetime();
         if (maxLifetime > 0) {
            // variance up to 2.5% of the maxlifetime
            final long variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0;
            final long lifetime = maxLifetime - variance;
            poolEntry.setFutureEol(houseKeepingExecutorService.schedule(new MaxLifetimeTask(poolEntry), lifetime, MILLISECONDS));
         }

         final long keepaliveTime = config.getKeepaliveTime();
         if (keepaliveTime > 0) {
            // variance up to 10% of the heartbeat time
            final long variance = ThreadLocalRandom.current().nextLong(keepaliveTime / 10);
            final long heartbeatTime = keepaliveTime - variance;
            poolEntry.setKeepalive(houseKeepingExecutorService.scheduleWithFixedDelay(new KeepaliveTask(poolEntry), heartbeatTime, heartbeatTime, MILLISECONDS));
         }

         return poolEntry;
      }
    //...
    return null;
}
  • newPoolEntry() 创建连接对象,它内部会创建db物理连接并且执行一下 connectionInitSql 语句
  • 如果设置了 maxLifetime(默认7小时) ,先随机减去 2.5% maxLifetime的时间,避免多个连接在同一个时间被清除掉,对db造成瞬时连接压力
    则会起一个任务 MaxLifeTimeTask 在这个连接创建后 maxLifetime 的时候将其清除(标记为 evict,如果此时连接空闲则直接关闭物理连接,不然要等到下次被取出时再关闭 HikariPool#geConnection 内逻辑)
  • 如果设置了 keepaliveTime (默认是0), 则开启定时任务,每隔 keepaliveTime(加了随机值) 检查db物理连接的可用性 jdbc4.isValid 或者执行下 connectionTestQuery 语句

maxLifetime 连接创建后的最大存活时间,超过后就会被清除
keepaliveTime 则是多久检查一次连接的活性,必须比 maxLifetime小 , 在申请到的连接空闲超过一定时间的话,在使用前也会记性 alive 活性判断,一般keepaliveTime 也没大必要

  • 创建成功的话,就退出循环了

3. 如果db连接创建失败,则休眠 250ms 后,再进入while逻辑,重新尝试

posted @ 2021-04-16 00:39  mushishi  阅读(775)  评论(0编辑  收藏  举报