(二)Druid数据库连接池如何获取Connection原理和源码分析?

(1)获取连接方法getConnectionDirect()线程:

这里是Druid的三个核心线程的交互逻辑图
(二)Druid数据库连接池如何获取Connection原理和源码分析?_第1张图片
⚠️这里是init();初始化在这一步:主要核心就是创建这几个线程

createAndLogThread();  //打印日志线程其实就是统计监控信息
createAndStartCreatorThread(); //创建连接的线程
createAndStartDestroyThread(); //销毁连接的线程
  • 首先第一大步骤就是先去获取DruidPooledConnection,通过getConnectionInternal()方法

    • 进入到方法内:

      1. 先进行一个for死循环当createDirect = true时跳出循环,首次为false,所以下一步重要的就是创建ScheduledThreadPoolExecutor 对象,条件就是当:【poolingCount(池子中的值为0时) && 活跃的连接 < maxActive && createScheduler != null && createScheduler instanceof ScheduledThreadPoolExecutor】 , 然后ScheduledThreadPoolExecutor中的getQueue().size() > 0 时,把createDirect = true,然后继续往下走,
      2. 然后通过我们设置的setMaxWait 时间进行判断,如果MaxWait > 0 ,就会从LRU的队列中的尾部取出一个connection使用方法 pollLast(nanos); 否则走takeLast();
      3. 如果DruidConnectionHolder 不为null ,把【connection】活跃的ActiveCount++,然后跳出循环
      4. 此时的createDirect = true,所以会去创建一个物理连接 赋值给 DruidConnectionHolder对象
      PhysicalConnectionInfo pyConnInfo = DruidDataSource.this.createPhysicalConnection();
      holder = new DruidConnectionHolder(this, pyConnInfo);
      
      1. 然后加锁,判断 activeCount < maxActive ,如果为True就把活跃的Connection连接进行➕1,跳出循环,如果 activeCount > maxActive,则需要丢弃创建好的这个创建好的物理连接
      JdbcUtils.close(pyConnInfo.getPhysicalConnection());
      
    • 如果成功继续走到下一步

    • 如果失败捕获住错误的话,就继续尝试获取DruidPooledConnection

  • 然后回到getConnectionDirect()方法中,走到第二个步骤中,先判断配置参数testOnBorrow是不是为True,然后去进行对连接进行校验,如果校验成功就继续往下走,

    boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
    if (!validate) {
        Connection realConnection = poolableConnection.conn;
        discardConnection(realConnection);
        continue;
    }
    
  • 如果配置参数testOnBorrow为True的话会先进行一次上面代码的校验如果testOnBorrow为False的话,并且 testWhileIdle参数为True的话,会再进行判断,如果【timeBetweenEvictionRunsMillis <= 0】直接使用 60s 进行填充

  • 继续走,如果当前连接的空闲时间idleMillis >= timeBetweenEvictionRunsMillis || idleMillis < 0】时,会继续进行校验当前连接的健康情况,和上面代码一样,如果校验不成功就会discard当前的Connection

  • 继续,然后判断配置参数removeAbandoned是不是为True,如果是就以当前连接poolableConnection 为Key,PRESENT作为Value放到activeConnections的Map集合中

  Map<DruidPooledConnection, Object> activeConnections                         = new IdentityHashMap<DruidPooledConnection, Object>();
//这里是判断逻辑
            if (removeAbandoned) {
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                poolableConnection.connectStackTrace = stackTrace;
                poolableConnection.setConnectedTimeNano();
                poolableConnection.traceEnable = true;

                activeConnectionLock.lock();
                try {
                    activeConnections.put(poolableConnection, PRESENT);
                } finally {
                    activeConnectionLock.unlock();
                }
            }
  • 继续,如果配置的defaultAutoCommit参数是不是为False,如果为False,执行,poolableConnection.setAutoCommit(false);
  • 最后 getConnectionDirect(long maxWaitMillis)方法 返回DruidPooledConnection 对象 poolableConnection

⚠️这里补充一下第一大步的第2小步中的pollLast(nanos)takeLast(nanos)方法中如果没有从LRU队列中的尾部获取到Connection时,就会发送图中的notify信号,去通知创建连接的线程去创建连接**

建议对照源码进行分析:

1. 先进入到getConnection方法中

    public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
        init();

        if (filters.size() > 0) {
            FilterChainImpl filterChain = new FilterChainImpl(this);
            return filterChain.dataSource_connect(this, maxWaitMillis);
        } else {
            return getConnectionDirect(maxWaitMillis);
        }
    }
  1. 然后进入到getConnectionDirect()方法中:
    public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
        int notFullTimeoutRetryCnt = 0;
        for (;;) {
            // handle notFullTimeoutRetry
            DruidPooledConnection poolableConnection;
            try {
            //这里的getConnectionInternal方法,其实对应的就是上面分析中的第一大步里面的逻辑
                poolableConnection = getConnectionInternal(maxWaitMillis);
            } catch (GetConnectionTimeoutException ex) {
                if (notFullTimeoutRetryCnt <= this.notFullTimeoutRetryCount && !isFull()) {
                    notFullTimeoutRetryCnt++;
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("get connection timeout retry : " + notFullTimeoutRetryCnt);
                    }
                    continue;
                }
                throw ex;
            }

            if (testOnBorrow) {
                boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
                if (!validate) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("skip not validate connection.");
                    }

                    Connection realConnection = poolableConnection.conn;
                    discardConnection(realConnection);
                    continue;
                }
            } else {
                Connection realConnection = poolableConnection.conn;
                if (poolableConnection.conn.isClosed()) {
                    discardConnection(null); // 传入null,避免重复关闭
                    continue;
                }

                if (testWhileIdle) {
                    final DruidConnectionHolder holder = poolableConnection.holder;
                    long currentTimeMillis             = System.currentTimeMillis();
                    long lastActiveTimeMillis          = holder.lastActiveTimeMillis;
                    long lastKeepTimeMillis            = holder.lastKeepTimeMillis;

                    if (lastKeepTimeMillis > lastActiveTimeMillis) {
                        lastActiveTimeMillis = lastKeepTimeMillis;
                    }

                    long idleMillis                    = currentTimeMillis - lastActiveTimeMillis;

                    long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;

                    if (timeBetweenEvictionRunsMillis <= 0) {
                        timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
                    }

                    if (idleMillis >= timeBetweenEvictionRunsMillis
                            || idleMillis < 0 // unexcepted branch
                            ) {
                        boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
                        if (!validate) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("skip not validate connection.");
                            }

                            discardConnection(realConnection);
                             continue;
                        }
                    }
                }
            }

            if (removeAbandoned) {
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                poolableConnection.connectStackTrace = stackTrace;
                poolableConnection.setConnectedTimeNano();
                poolableConnection.traceEnable = true;

                activeConnectionLock.lock();
                try {
                    activeConnections.put(poolableConnection, PRESENT);
                } finally {
                    activeConnectionLock.unlock();
                }
            }

            if (!this.defaultAutoCommit) {
                poolableConnection.setAutoCommit(false);
            }

            return poolableConnection;
        }
    }

参考文章:http://zhengjianglong.cn/2019/07/14/framework/druid-db-connection/

你可能感兴趣的:(【Druid】)