Hikari连接池1--初始化连接池

基于SpringBoot 2.2.7.RELEASE 依赖的 HikariCP 3.4.3。
源码包中源码和实际Class文件反编译代码有出入,以Class反编译代码为准。
Hikari连接池有两篇
Hikari连接池1–初始化连接池
Hikari连接池2–获取和归还连接
Hikari有两个连接池

private final HikariPool fastPathPool;
private volatile HikariPool pool;

1、默认构造器

public HikariDataSource() {
    super();
    //将 fastPathPool 置空
    fastPathPool = null;
}

HikariDataSource 继承 HikariConfig,super 调的是 HikariConfig 的构造方法。

HikariDataSource 也实现了 DataSource 接口

public HikariConfig() {
    dataSourceProperties = new Properties();
    healthCheckProperties = new Properties();

    minIdle = -1;
    maxPoolSize = -1;
    maxLifetime = MAX_LIFETIME;
    connectionTimeout = CONNECTION_TIMEOUT;
    validationTimeout = VALIDATION_TIMEOUT;
    idleTimeout = IDLE_TIMEOUT;
    initializationFailTimeout = 1;
    isAutoCommit = true;

    String systemProp = System.getProperty("hikaricp.configurationFile");
    if (systemProp != null) {
        loadProperties(systemProp);
    }
}

使用 HikariDataSource 的默认构造方法创建数据源,多次创建,其父 HikariConfig 只有一个。

并且,这个构造器没有初始化连接池。

2、带参构造器

public HikariDataSource(HikariConfig configuration){
    //校验
    configuration.validate();
    //拷贝属性
    configuration.copyStateTo(this);

    LOGGER.info("{} - Starting...", configuration.getPoolName());
    //创建新的连接池
    pool = fastPathPool = new HikariPool(this);
    LOGGER.info("{} - Start completed.", configuration.getPoolName());
	//设置标志
    this.seal();
}

创建 HikariPool

public HikariPool(final HikariConfig config) {
    //调用父类构造器初始化数据源
    super(config);
	//创建bag
    this.connectionBag = new ConcurrentBag<>(this);
    //创建Semaphore锁
    this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK;
	//创建线程池
    this.houseKeepingExecutorService = initializeHouseKeepingExecutorService();
	//初始化连接池,向连接池里放连接
    checkFailFast();

    if (config.getMetricsTrackerFactory() != null) {
        setMetricsTrackerFactory(config.getMetricsTrackerFactory());
    }
    else {
        setMetricRegistry(config.getMetricRegistry());
    }

    setHealthCheckRegistry(config.getHealthCheckRegistry());

    handleMBeans(this, true);

    ThreadFactory threadFactory = config.getThreadFactory();

    final int maxPoolSize = config.getMaximumPoolSize();
    LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(maxPoolSize);
    this.addConnectionQueueReadOnlyView = unmodifiableCollection(addConnectionQueue);
    this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
    this.closeConnectionExecutor = createThreadPoolExecutor(maxPoolSize, poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());

    this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService);

    this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, housekeepingPeriodMs, MILLISECONDS);

    if (Boolean.getBoolean("com.zaxxer.hikari.blockUntilFilled") && config.getInitializationFailTimeout() > 1) {
        addConnectionExecutor.setCorePoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));
        addConnectionExecutor.setMaximumPoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));

        final long startTime = currentTime();
        while (elapsedMillis(startTime) < config.getInitializationFailTimeout() && getTotalConnections() < config.getMinimumIdle()) {
            quietlySleep(MILLISECONDS.toMillis(100));
        }

        addConnectionExecutor.setCorePoolSize(1);
        addConnectionExecutor.setMaximumPoolSize(1);
    }
}

2.1、初始化数据源

HikariPool的父类

PoolBase(final HikariConfig config) {
    this.config = config;

    this.networkTimeout = UNINITIALIZED;
    this.catalog = config.getCatalog();
    this.schema = config.getSchema();
    this.isReadOnly = config.isReadOnly();
    this.isAutoCommit = config.isAutoCommit();
    this.exceptionOverride = UtilityElf.createInstance(config.getExceptionOverrideClassName(), SQLExceptionOverride.class);
    this.transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation());

    this.isQueryTimeoutSupported = UNINITIALIZED;
    this.isNetworkTimeoutSupported = UNINITIALIZED;
    this.isUseJdbc4Validation = config.getConnectionTestQuery() == null;
    this.isIsolateInternalQueries = config.isIsolateInternalQueries();

    this.poolName = config.getPoolName();
    this.connectionTimeout = config.getConnectionTimeout();
    this.validationTimeout = config.getValidationTimeout();
    this.lastConnectionFailure = new AtomicReference<>();
	//初始化数据源
    initializeDataSource();
}

初始化DataSource

private void initializeDataSource() {
    final String jdbcUrl = config.getJdbcUrl();
    final String username = config.getUsername();
    final String password = config.getPassword();
    final String dsClassName = config.getDataSourceClassName();
    final String driverClassName = config.getDriverClassName();
    final String dataSourceJNDI = config.getDataSourceJNDI();
    final Properties dataSourceProperties = config.getDataSourceProperties();
	//DataSource 为空,创建
    DataSource ds = config.getDataSource();
    if (dsClassName != null && ds == null) {
        ds = createInstance(dsClassName, DataSource.class);
        PropertyElf.setTargetFromProperties(ds, dataSourceProperties);
    }
    else if (jdbcUrl != null && ds == null) {//一般会执行这里
        ds = new DriverDataSource(jdbcUrl, driverClassName, dataSourceProperties, username, password);
    }
    else if (dataSourceJNDI != null && ds == null) {
        try {
            InitialContext ic = new InitialContext();
            ds = (DataSource) ic.lookup(dataSourceJNDI);
        } catch (NamingException e) {
            throw new PoolInitializationException(e);
        }
    }

    if (ds != null) {
        //设置登录超时时间
        setLoginTimeout(ds);
        //创建网络超时执行器
        createNetworkTimeoutExecutor(ds, dsClassName, jdbcUrl);
    }

    this.dataSource = ds;
}

创建数据源

public DriverDataSource(String jdbcUrl, String driverClassName, Properties properties, String username, String password) {
    this.jdbcUrl = jdbcUrl;
    this.driverProperties = new Properties();

    for (Entry<Object, Object> entry : properties.entrySet()) {
        driverProperties.setProperty(entry.getKey().toString(), entry.getValue().toString());
    }

    if (username != null) {
        driverProperties.put(USER, driverProperties.getProperty("user", username));
    }
    if (password != null) {
        driverProperties.put(PASSWORD, driverProperties.getProperty("password", password));
    }

    if (driverClassName != null) {
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver d = drivers.nextElement();
            if (d.getClass().getName().equals(driverClassName)) {
                driver = d;
                break;
            }
        }

        if (driver == null) {
            LOGGER.warn("Registered driver with driverClassName={} was not found, trying direct instantiation.", driverClassName);
            Class<?> driverClass = null;
            ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader();
            try {
                if (threadContextClassLoader != null) {
                    try {
                        driverClass = threadContextClassLoader.loadClass(driverClassName);
                        LOGGER.debug("Driver class {} found in Thread context class loader {}", driverClassName, threadContextClassLoader);
                    }
                    catch (ClassNotFoundException e) {
                        LOGGER.debug("Driver class {} not found in Thread context class loader {}, trying classloader {}",
                                     driverClassName, threadContextClassLoader, this.getClass().getClassLoader());
                    }
                }

                if (driverClass == null) {
                    driverClass = this.getClass().getClassLoader().loadClass(driverClassName);
                    LOGGER.debug("Driver class {} found in the HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
                }
            } catch (ClassNotFoundException e) {
                LOGGER.debug("Failed to load driver class {} from HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
            }

            if (driverClass != null) {
                try {
                    //初始化驱动
                    driver = (Driver) driverClass.newInstance();
                } catch (Exception e) {
                    LOGGER.warn("Failed to create instance of driver class {}, trying jdbcUrl resolution", driverClassName, e);
                }
            }
        }
    }

    final String sanitizedUrl = jdbcUrl.replaceAll("([?&;]password=)[^&#;]*(.*)", "$1<masked>$2");
    try {
        if (driver == null) {
            driver = DriverManager.getDriver(jdbcUrl);
            LOGGER.debug("Loaded driver with class name {} for jdbcUrl={}", driver.getClass().getName(), sanitizedUrl);
        }
        else if (!driver.acceptsURL(jdbcUrl)) {
            throw new RuntimeException("Driver " + driverClassName + " claims to not accept jdbcUrl, " + sanitizedUrl);
        }
    }
    catch (SQLException e) {
        throw new RuntimeException("Failed to get driver instance for jdbcUrl=" + sanitizedUrl, e);
    }
}

2.2、初始化连接池

private final ConcurrentBag<PoolEntry> connectionBag;
//com.zaxxer.hikari.pool.HikariPool#checkFailFast
private void checkFailFast() {
    final long initializationTimeout = config.getInitializationFailTimeout();
    if (initializationTimeout < 0) {
        return;
    }

    final long startTime = currentTime();
    do {
        //创建entry
        final PoolEntry poolEntry = createPoolEntry();
        //entry不为空,将entry设置到bag里面,这是初始化时创建的一条连接
        if (poolEntry != null) {
            if (config.getMinimumIdle() > 0) {
                //添加到连接池
                connectionBag.add(poolEntry);
                logger.debug("{} - Added connection {}", poolName, poolEntry.connection);
            }
            else {
                quietlyCloseConnection(poolEntry.close(), "(initialization check complete and minimumIdle is zero)");
            }

            return;
        }

        if (getLastConnectionFailure() instanceof ConnectionSetupException) {
            throwPoolInitializationException(getLastConnectionFailure().getCause());
        }

        quietlySleep(SECONDS.toMillis(1));
    } while (elapsedMillis(startTime) < initializationTimeout);

    if (initializationTimeout > 0) {
        throwPoolInitializationException(getLastConnectionFailure());
    }
}

2.2.1、创建连接

//com.zaxxer.hikari.pool.HikariPool#createPoolEntry
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(
                () -> {
                    if (softEvictConnection(poolEntry, "(connection has passed maxLifetime)", false /* not owner */)) {
                        addBagItem(connectionBag.getWaitingThreadCount());
                    }
                },
                lifetime, MILLISECONDS));
        }

        return poolEntry;
    }
    catch (ConnectionSetupException e) {
        if (poolState == POOL_NORMAL) { // we check POOL_NORMAL to avoid a flood of messages if shutdown() is running concurrently
            logger.error("{} - Error thrown while acquiring connection from data source", poolName, e.getCause());
            lastConnectionFailure.set(e);
        }
    }
    catch (Exception e) {
        if (poolState == POOL_NORMAL) { // we check POOL_NORMAL to avoid a flood of messages if shutdown() is running concurrently
            logger.debug("{} - Cannot acquire connection from data source", poolName, e);
        }
    }

    return null;
}

创建连接

//com.zaxxer.hikari.pool.PoolBase#newPoolEntry
PoolEntry newPoolEntry() throws Exception {
    return new PoolEntry(newConnection(), this, isReadOnly, isAutoCommit);
}

2.2.1.1、创建连接
//com.zaxxer.hikari.pool.PoolBase#newConnection
private Connection newConnection() throws Exception {
    final long start = currentTime();

    Connection connection = null;
    try {
        String username = config.getUsername();
        String password = config.getPassword();
		//获取连接
        connection = (username == null) ? dataSource.getConnection() : dataSource.getConnection(username, password);
        if (connection == null) {
            throw new SQLTransientConnectionException("DataSource returned null unexpectedly");
        }
		//设置连接属性
        setupConnection(connection);
        lastConnectionFailure.set(null);
        return connection;
    }
    catch (Exception e) {
        if (connection != null) {
            quietlyCloseConnection(connection, "(Failed to create/setup connection)");
        }
        else if (getLastConnectionFailure() == null) {
            logger.debug("{} - Failed to create/setup connection: {}", poolName, e.getMessage());
        }

        lastConnectionFailure.set(e);
        throw e;
    }
    finally {
        // tracker will be null during failFast check
        if (metricsTracker != null) {
            metricsTracker.recordConnectionCreated(elapsedMillis(start));
        }
    }
}

2.2.1.1.1、获取链接
//com.zaxxer.hikari.util.DriverDataSource#getConnection
public Connection getConnection(final String username, final String password) throws SQLException {
    final Properties cloned = (Properties) driverProperties.clone();
    if (username != null) {
        cloned.put("user", username);
        if (cloned.containsKey("username")) {
            cloned.put("username", username);
        }
    }
    if (password != null) {
        cloned.put("password", password);
    }
	//从数据库驱动获取连接
    return driver.connect(jdbcUrl, cloned);
}

2.2.1.2、设置连接属性
//com.zaxxer.hikari.pool.PoolBase#setupConnection
private void setupConnection(final Connection connection) throws ConnectionSetupException {
    try {
        if (networkTimeout == UNINITIALIZED) {
            networkTimeout = getAndSetNetworkTimeout(connection, validationTimeout);
        }
        else {
            setNetworkTimeout(connection, validationTimeout);
        }

        if (connection.isReadOnly() != isReadOnly) {
            connection.setReadOnly(isReadOnly);
        }

        if (connection.getAutoCommit() != isAutoCommit) {
            connection.setAutoCommit(isAutoCommit);
        }
		//检查驱动
        checkDriverSupport(connection);

        if (transactionIsolation != defaultTransactionIsolation) {
            connection.setTransactionIsolation(transactionIsolation);
        }

        if (catalog != null) {
            connection.setCatalog(catalog);
        }

        if (schema != null) {
            connection.setSchema(schema);
        }
		//执行sql
        executeSql(connection, config.getConnectionInitSql(), true);

        setNetworkTimeout(connection, networkTimeout);
    }
    catch (SQLException e) {
        throw new ConnectionSetupException(e);
    }
}

执行初始化sql

//com.zaxxer.hikari.pool.PoolBase#executeSql
private void executeSql(final Connection connection, final String sql, final boolean isCommit) throws SQLException {
    if (sql != null) {
        try (Statement statement = connection.createStatement()) {
            // connection was created a few milliseconds before, so set query timeout is omitted (we assume it will succeed)
            //执行sql
            statement.execute(sql);
        }

        if (isIsolateInternalQueries && !isAutoCommit) {
            if (isCommit) {
                connection.commit();
            }
            else {
                connection.rollback();
            }
        }
    }
}

2.2.1.2、创建PoolEntry
PoolEntry(final Connection connection, final PoolBase pool, final boolean isReadOnly, final boolean isAutoCommit) {
    this.connection = connection;
    this.hikariPool = (HikariPool) pool;
    this.isReadOnly = isReadOnly;
    this.isAutoCommit = isAutoCommit;
    this.lastAccessed = currentTime();
    this.openStatements = new FastList<>(Statement.class, 16);
}
2.2.2、向bag添加连接
private final CopyOnWriteArrayList<T> sharedList;
//com.zaxxer.hikari.util.ConcurrentBag#add
public void add(final T bagEntry) {
    if (closed) {
        LOGGER.info("ConcurrentBag has been closed, ignoring add()");
        throw new IllegalStateException("ConcurrentBag has been closed, ignoring add()");
    }
	//添加到sharedList
    sharedList.add(bagEntry);

    // spin until a thread takes it or none are waiting
    while (waiters.get() > 0 && bagEntry.getState() == STATE_NOT_IN_USE && !handoffQueue.offer(bagEntry)) {
        Thread.yield();
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
连接池是一种用于管理数据库连接的技术,它可以提高数据库的性能和可扩展性。下面是使用HikariCP连接池进行初始化的一些步骤: 1. 首先,确保你已经将HikariCP作为依赖项添加到你的项目中。你可以在Maven或Gradle的配置文件中添加相应的依赖。 2. 在你的应用程序的配置文件中,添加连接池的相关配置。这些配置包括数据库的URL、用户名、密码等信息。以下是一个示例配置: ``` spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.minimum-idle=5 ``` 在这个示例中,我们使用了Spring Boot的配置方式,也可以根据你的项目和框架选择合适的方式。 3. 创建一个HikariDataSource对象,并将配置信息传递给它。你可以在应用程序的启动过程中完成这个步骤。以下是一个示例代码: ```java @Configuration public class DataSourceConfig { @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public DataSource dataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl(url); config.setUsername(username); config.setPassword(password); return new HikariDataSource(config); } } ``` 在这个示例中,我们使用了Spring的配置方式,将配置信息注入到DataSource bean中。 4. 现在,你可以在你的应用程序中使用连接池了。你可以通过从DataSource bean获取连接来操作数据库。以下是一个示例代码: ```java @Service public class MyService { private final DataSource dataSource; public MyService(DataSource dataSource) { this.dataSource = dataSource; } public void doSomething() { try (Connection connection = dataSource.getConnection()) { // 使用连接进行数据库操作 } catch (SQLException e) { // 处理异常 } } } ``` 在这个示例中,我们通过依赖注入的方式获取了DataSource对象,并使用它获取数据库连接。 这就是使用HikariCP连接池进行初始化的一般步骤。你可以根据自己的项目需求和框架选择合适的配置方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值