Hikari连接的创建过程
HouseKeeper 和 HikariPool#addBagItem 在需要新增db连接的时候,都是往负责连接创建的线程池 addConnectionExecutor 丢PoolEntryCreator 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逻辑,重新尝试
本文来自博客园,作者:mushishi,转载请注明原文链接:https://www.cnblogs.com/mushishi/p/14665233.html