Druid-代码段-1-1

所属文章:池化技术(一)Druid是如何管理数据库连接的?

 本代码段对应主流程1,具体用来获取一个连接:


lic DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
        init(); //初始化,即主流程2

        if (filters.size() > 0) {
            FilterChainImpl filterChain = new FilterChainImpl(this); //责任链,内部也是触发下面的getConnectionDirect方法,只是要走一遍责任链上每个filter的逻辑,这里不做描述,后续放到流程1.1里体现
            return filterChain.dataSource_connect(this, maxWaitMillis);
        } else {
            return getConnectionDirect(maxWaitMillis); //触发getConnectionDirect
        }
    }

    public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
        int notFullTimeoutRetryCnt = 0;
        for (;;) { //死循环
            /**
             * 真正返回出去的连接对象,注意这里是被druid包装成了DruidPooledConnection类型,
             * 实际上池子里存放的连接类型是DruidConnectionHolder,DruidPooledConnection类本身持有一个holder属性,
             * 用于保存真正的连接对象,而DruidConnectionHolder才是真正保存驱动连接对象的类。
             */
            DruidPooledConnection poolableConnection;
            try {
                poolableConnection = getConnectionInternal(maxWaitMillis); //从池子里获取连接,这一个后续放到流程1.2体现
            } catch (GetConnectionTimeoutException ex) {
                if (notFullTimeoutRetryCnt <= this.notFullTimeoutRetryCount && !isFull()) { //出现了超时异常,在连接池没满且重试次数未超过上限的情况下,重试一次(notFullTimeoutRetryCount默认是0,所以至少可以重试一次)。
                    notFullTimeoutRetryCnt++; //重试次数+1
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("get connection timeout retry : " + notFullTimeoutRetryCnt);
                    }
                    continue;
                }
                throw ex; //超过重试次数或者池子已满仍然获取失败,则直接抛出异常
            }

            if (testOnBorrow) { //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); //若连接不可用,则触发discard,这个方法具体放到流程1.4体现
                    continue;
                }
            } else {
                Connection realConnection = poolableConnection.conn;
                if (poolableConnection.conn.isClosed()) {
                    discardConnection(null); // 传入null,避免重复关闭
                    continue;
                }

                if (testWhileIdle) { //不启用testOnBorrow的情况下,才会判断是否启用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) { //当闲置时间超出timeBetweenEvictionRunsMillis(默认60s)时,则触发检查逻辑
                        boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
                        if (!validate) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("skip not validate connection.");
                            }

                            discardConnection(realConnection); //连接不可用,同样触发discard
                            continue;
                        }
                    }
                }
            }

            if (removeAbandoned) { //若开启removeAbandoned,则把当前拿到的连接放到activeConnections里,方便后续检查(后面流程4.2体现)
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                poolableConnection.connectStackTrace = stackTrace;
                poolableConnection.setConnectedTimeNano(); //设置连接获取时间为当前时间
                poolableConnection.traceEnable = true; //这个设置为true,则在归还该连接时会在activeConnections里清除掉该连接对象

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

            if (!this.defaultAutoCommit) { //默认是不开事务的,所以这里是true,不会触发下面的逻辑;这个不建议手动设置默认值,一般开启事务的工作自己做或者交给第三方框架(如spring)做比较好
                poolableConnection.setAutoCommit(false);
            }

            return poolableConnection; //最终返回可用连接
        }
    }
posted @ 2019-09-18 05:36  是胖虎捏  阅读(687)  评论(0编辑  收藏  举报