This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021

Introduction to the

After exploring the key code for Alibaba Druid’s connection pool initialization and getting connections, let’s look at the initialization section in more detail

The database connection pool is initialized

Comment the entire code as follows:

public void init(a) throws SQLException {
        // It has already been initialized
        if (inited) {
            return;
        }

        // bug fixed for dead lock, for issue #2980
        DruidDriver.getInstance();

        // Lock during initialization
        final ReentrantLock lock = this.lock;
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            throw new SQLException("interrupt", e);
        }

        boolean init = false;
        try {
            if (inited) {
                return;
            }

            initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());

            // This part is not clear
            this.id = DruidDriver.createDataSourceId();
            if (this.id > 1) {
                long delta = (this.id - 1) * 100000;
                this.connectionIdSeedUpdater.addAndGet(this, delta);
                this.statementIdSeedUpdater.addAndGet(this, delta);
                this.resultSetIdSeedUpdater.addAndGet(this, delta);
                this.transactionIdSeedUpdater.addAndGet(this, delta);
            }

            // Database connection URL
            if (this.jdbcUrl ! =null) {
                this.jdbcUrl = this.jdbcUrl.trim();
                initFromWrapDriverUrl();
            }

            // filter is associated and is currently empty
            for (Filter filter : filters) {
                filter.init(this);
            }

            // Get the database type
            if (this.dbTypeName == null || this.dbTypeName.length() == 0) {
                this.dbTypeName = JdbcUtils.getDbType(jdbcUrl, null);
            }

            Mysql, Mariadb, Oceanbase, ADS
            DbType dbType = DbType.of(this.dbTypeName);
            if (dbType == DbType.mysql
                    || dbType == DbType.mariadb
                    || dbType == DbType.oceanbase
                    || dbType == DbType.ads) {
                boolean cacheServerConfigurationSet = false;
                if (this.connectProperties.containsKey("cacheServerConfiguration")) {
                    cacheServerConfigurationSet = true;
                } else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {
                    cacheServerConfigurationSet = true;
                }
                if (cacheServerConfigurationSet) {
                    this.connectProperties.put("cacheServerConfiguration"."true"); }}// Here are some examples of the configuration
            // Would it be better to put this part first?
            if (maxActive <= 0) {
                throw new IllegalArgumentException("illegal maxActive " + maxActive);
            }

            if (maxActive < minIdle) {
                throw new IllegalArgumentException("illegal maxActive " + maxActive);
            }

            if (getInitialSize() > maxActive) {
                throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActive " + maxActive);
            }

            if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) {
                throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true");
            }

            if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
                throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
            }

            if (keepAlive && keepAliveBetweenTimeMillis <= timeBetweenEvictionRunsMillis) {
                throw new SQLException("keepAliveBetweenTimeMillis must be grater than timeBetweenEvictionRunsMillis");
            }

            / / driverClass related
            if (this.driverClass ! =null) {
                this.driverClass = driverClass.trim();
            }

            // This section has some initial loading and checking, but it is not very clear
            initFromSPIServiceLoader();

            resolveDriver();

            initCheck();

            initExceptionSorter();
            initValidConnectionChecker();
            validationQueryCheck();

            // It is not clear what Stat does
            if (isUseGlobalDataSourceStat()) {
                dataSourceStat = JdbcDataSourceStat.getGlobal();
                if (dataSourceStat == null) {
                    dataSourceStat = new JdbcDataSourceStat("Global"."Global".this.dbTypeName);
                    JdbcDataSourceStat.setGlobal(dataSourceStat);
                }
                if (dataSourceStat.getDbType() == null) {
                    dataSourceStat.setDbType(this.dbTypeName); }}else {
                dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbTypeName, this.connectProperties);
            }
            dataSourceStat.setResetStatEnable(this.resetStatEnable);

            // Key database connection pool-related, which is obtained from DruidConnectionHolder in connection obtaining
            connections = new DruidConnectionHolder[maxActive];
            evictConnections = new DruidConnectionHolder[maxActive];
            keepAliveConnections = new DruidConnectionHolder[maxActive];

            SQLException connectError = null;

            // Create a database physical connection asynchronously
            DruidConnectionHolder = DruidConnectionHolder = DruidConnectionHolder = DruidConnectionHolder
            if(createScheduler ! =null && asyncInit) {
                for (int i = 0; i < initialSize; ++i) {
                    submitCreateTask(true); }}else if(! asyncInit) {// init connections
                while (poolingCount < initialSize) {
                    try {
                        PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
                        DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
                        connections[poolingCount++] = holder;
                    } catch (SQLException ex) {
                        LOG.error("init datasource error, url: " + this.getUrl(), ex);
                        if (initExceptionThrow) {
                            connectError = ex;
                            break;
                        } else {
                            Thread.sleep(3000); }}}if (poolingCount > 0) { poolingPeak = poolingCount; poolingPeakTime = System.currentTimeMillis(); }}// Some auxiliary initialization operations such as logging
            createAndLogThread();
            createAndStartCreatorThread();
            createAndStartDestroyThread();

            initedLatch.await();
            init = true;

            initedTime = new Date();
            registerMbean();

            if(connectError ! =null && poolingCount == 0) {
                throw connectError;
            }

            // initialSize is the initial number of connections
            // This is keepAlive
            if (keepAlive) {
                // async fill to minIdle
                if(createScheduler ! =null) {
                    for (int i = 0; i < minIdle; ++i) {
                        submitCreateTask(true); }}else {
                    this.emptySignal(); }}}catch (SQLException e) {
            LOG.error("{dataSource-" + this.getID() + "} init error", e);
            throw e;
        } catch (InterruptedException e) {
            throw new SQLException(e.getMessage(), e);
        } catch (RuntimeException e){
            LOG.error("{dataSource-" + this.getID() + "} init error", e);
            throw e;
        } catch (Error e){
            LOG.error("{dataSource-" + this.getID() + "} init error", e);
            throw e;

        } finally {
            inited = true;
            lock.unlock();

            if (init && LOG.isInfoEnabled()) {
                String msg = "{dataSource-" + this.getID();

                if (this.name ! =null&&!this.name.isEmpty()) {
                    msg += ",";
                    msg += this.name;
                }

                msg += "} inited"; LOG.info(msg); }}}Copy the code

conclusion

As can be seen from above:

  • Initializing a double-checked lock
  • The database can generate the configured initial number of connections asynchronously or synchronously
  • If keepalive is true, the configured minimum number of idle connections is generated asynchronously

I only have a brief understanding of the entire initialization process, but there are so many details that I feel I don’t understand the business scenario well enough