第七章、testWhileIdle、testOnBorrow、testOnReturn 在探活的应用

testOnBorrow申请连接时执行validationQuery 配置的探活语句检测连接是否有效。
testWhileIdle申请连接的时候检测,如果空闲时间于timeBetweenEvictionRunsMillis ,执 validationQuery 检测连接是否有效
testOnReturn归还连接时执 validationQuery 检测连接是否有效。
timeBetweenEvictionRunsMillistestWhileIdle 的判断依据

testOnBorrow 和 testWhileIdle

com.alibaba.druid.pool.DruidDataSource#getConnectionDirect

// 获取连接时检测连接有效性
if (testOnBorrow) {
    // 连接检测
    boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
    if (!validate) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("skip not validate connection.");
        }
        discardConnection(poolableConnection.holder);
        continue;
    }
} else {
    // 因为没有做连接检测,需要判断一下
    if (poolableConnection.conn.isClosed()) {
        discardConnection(poolableConnection.holder); // 传入null,避免重复关闭
        continue;
    }
    // testOnBorrow为false 是testWhileIdle的前提
    if (testWhileIdle) {
        final DruidConnectionHolder holder = poolableConnection.holder;
        //  当前时间
        long currentTimeMillis = System.currentTimeMillis();
        // 上一次连接活跃时间
        long lastActiveTimeMillis = holder.lastActiveTimeMillis;
        long lastExecTimeMillis = holder.lastExecTimeMillis;
        // 上一个保存时间
        long lastKeepTimeMillis = holder.lastKeepTimeMillis;
        if (checkExecuteTime
                && lastExecTimeMillis != lastActiveTimeMillis) {
            lastActiveTimeMillis = lastExecTimeMillis;
        }
        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(poolableConnection.holder);
                continue;
            }
        }
    }
}

testOnReturn

com.alibaba.druid.pool.DruidDataSource#recycle

if (testOnReturn) {
    boolean validate = testConnectionInternal(holder, physicalConnection);
    if (!validate) {
        // 关闭实际连接
        JdbcUtils.close(physicalConnection);
        destroyCountUpdater.incrementAndGet(this);
        lock.lock();
        try {
            if (holder.active) {
                // 活动线程数-1
                activeCount--;
                // holder活动状态置为false
                holder.active = false;
            }
            closeCount++;
        } finally {
            lock.unlock();
        }
        // 由于没有把资源回收到池中,这个holder会被回收掉
        return;
    }
}

testConnectionInternal

三个参数都需要的探活方法 testConnectionInternal

com.alibaba.druid.pool.DruidAbstractDataSource#testConnectionInternal(com.alibaba.druid.pool.DruidConnectionHolder, java.sql.Connection)

	protected boolean testConnectionInternal(DruidConnectionHolder holder, Connection conn) {

            if (validConnectionChecker != null) {
             
                //`com.alibaba.druid.pool.DruidDataSource#initValidConnectionChecker` 在 `DruidDataSource#init` 方法中执行
                //会根据不同的数据库类型初始化不同的检测器
                // 如mysql,如果开启ping方法会直接使用jdbc驱动提供的更轻量级探活机制,否则使用select 1
                boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);
                long currentTimeMillis = System.currentTimeMillis();
                if (holder != null) {
                    // 会更新连接上次可用时间
                    holder.lastValidTimeMillis = currentTimeMillis;
                    holder.lastExecTimeMillis = currentTimeMillis;
                }
              
                return valid;
            }

            if (conn.isClosed()) {
                return false;
            }

            if (null == validationQuery) {
                return true;
            }

            Statement stmt = null;
            ResultSet rset = null;
            try {
                stmt = conn.createStatement();
                if (getValidationQueryTimeout() > 0) {
                    stmt.setQueryTimeout(validationQueryTimeout);
                }
                rset = stmt.executeQuery(validationQuery);
                if (!rset.next()) {
                    return false;
                }
            } finally {
                JdbcUtils.close(rset);
                JdbcUtils.close(stmt);
            }
     
    }

discardConnection

	public void discardConnection(DruidConnectionHolder holder) {
        if (holder == null) {
            return;
        }

        Connection conn = holder.getConnection();
        if (conn != null) {
            JdbcUtils.close(conn);
        }

        lock.lock();
        try {
            if (holder.discard) {
                return;
            }

            if (holder.active) {
                activeCount--;
                holder.active = false;
            }
            discardCount++;

            holder.discard = true;

			// 如果可用连接数量小于最小空闲连接数量,唤起创建连接的线程
            if (activeCount <= minIdle) {
                emptySignal();
            }
        } finally {
            lock.unlock();
        }
    }

版权声明:本文为abcd2136169原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。