Druid-代码段-5-1

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

本代码段对应主流程5,连接的回收:


//DruidPooledConnection类的close方法
    @Override
    public void close() throws SQLException {
        if (this.disable) { //检查,因为该连接对象是抛出去给别的业务线程使用,也就是说并不受连接池本身管控,所以很可能存在多线程同时close的操作,因此这里需要做一层检查,包括下方的syncClose里的检查也是一个意思
            return;
        }

        DruidConnectionHolder holder = this.holder; //拿到对应的holder对象(之前说过,这个对象才是最后放进连接池的对象)
        if (holder == null) {
            if (dupCloseLogEnable) {
                LOG.error("dup close");
            }
            return;
        }

        DruidAbstractDataSource dataSource = holder.getDataSource(); //拿到对应的连接池对象
        boolean isSameThread = this.getOwnerThread() == Thread.currentThread();

        if (!isSameThread) { //关闭该连接与获取该连接的线程并非同一个的时候,则触发下面的syncClose
            dataSource.setAsyncCloseConnectionEnable(true);
        }

        if (dataSource.isAsyncCloseConnectionEnable()) {
            syncClose(); //参考上面的解释,该方法详情在下方
            return;
        }

        //一些事件监听器的触发,忽略
        for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {
            listener.connectionClosed(new ConnectionEvent(this));
        }


        //责任链的执行,参考流程1.1与代码段1-2,运行方式是一样的,找到映射方法,整个触发一遍责任链上的filters
        List filters = dataSource.getProxyFilters();
        if (filters.size() > 0) {
            FilterChainImpl filterChain = new FilterChainImpl(dataSource);
            filterChain.dataSource_recycle(this);
        } else {
            recycle(); //触发目标方法recycle
        }

        this.disable = true; //标记该连接已失效,无法再次提供服务
    }



    //上面逻辑走syncClose的情况,该方法与上面大体相同,但由于不是同一个线程做的操作,所以这里需要锁控制
    public void syncClose() throws SQLException {
        lock.lock(); //获取锁,这个锁是当前连接对象上的锁,为了解决同一个连接对象在不同的线程里被同时close多次而造成的线程安全问题
        try {
            if (this.disable) {
                return;
            }

            DruidConnectionHolder holder = this.holder; //同样的,拿到需要归还的holder对象
            if (holder == null) {
                if (dupCloseLogEnable) {
                    LOG.error("dup close");
                }
                return;
            }

            //同样是一些事件监听器的触发,忽略
            for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {
                listener.connectionClosed(new ConnectionEvent(this));
            }

            //同样的责任链的执行,参考上面的解释
            DruidAbstractDataSource dataSource = holder.getDataSource();
            List filters = dataSource.getProxyFilters();
            if (filters.size() > 0) {
                FilterChainImpl filterChain = new FilterChainImpl(dataSource);
                filterChain.dataSource_recycle(this);
            } else {
                recycle(); //触发目标方法recycle,方法详情在下方
            }

            this.disable = true; //标记该连接已失效,无法再次提供服务
        } finally {
            lock.unlock(); //解锁
        }
    }


    //DruidPooledConnection类的recycle方法,由上面俩方法直接触发
    public void recycle() throws SQLException {
        if (this.disable) {
            return;
        }

        DruidConnectionHolder holder = this.holder; //拿到真正需要归还的连接对象
        if (holder == null) {
            if (dupCloseLogEnable) {
                LOG.error("dup close");
            }
            return;
        }

        if (!this.abandoned) { //如果期间已经被流程4.2处理过了(abandoned==true),则不触发下方逻辑
            DruidAbstractDataSource dataSource = holder.getDataSource();
            dataSource.recycle(this); //真正触发连接池的回收方法,方法详情在下方
        }

        //连接对象一旦被回收处理,则会把所有与连接相关的属性置空(不持有),closed标记为true
        this.holder = null;
        conn = null;
        transactionInfo = null;
        closed = true;
    }

    //DruidDataSource类里的recycle方法,真正回收连接的方法,由上面DruidPooledConnection类的recycle触发
    protected void recycle(DruidPooledConnection pooledConnection) throws SQLException {
        final DruidConnectionHolder holder = pooledConnection.holder;

        if (holder == null) {
            LOG.warn("connectionHolder is null");
            return;
        }

        if (logDifferentThread //
                && (!isAsyncCloseConnectionEnable()) //
                && pooledConnection.ownerThread != Thread.currentThread()//
        ) {
            LOG.warn("get/close not same thread");
        }

        final Connection physicalConnection = holder.conn; //拿到真正的驱动连接对象

        if (pooledConnection.traceEnable) { //如果traceEnable为true(满足该属性为true,必须要removeAbandoned设置为true,这样在主流程1那里才会被放进activeConnections,才会置为true),流程4.2处理过后,会把该属性重新置为false,其他情况均为true
            Object oldInfo = null;
            activeConnectionLock.lock();
            try {
                if (pooledConnection.traceEnable) { //双重检查
                    oldInfo = activeConnections.remove(pooledConnection); //从activeConnections移除,防止流程4.2的重复检查
                    pooledConnection.traceEnable = false; //置为false
                }
            } finally {
                activeConnectionLock.unlock();
            }
            if (oldInfo == null) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn("remove abandonded failed. activeConnections.size " + activeConnections.size());
                }
            }
        }

        final boolean isAutoCommit = holder.underlyingAutoCommit;
        final boolean isReadOnly = holder.underlyingReadOnly;
        final boolean testOnReturn = this.testOnReturn;

        try {
            // 如果在归还至连接池时发现此连接对象还有未处理完的事务,则直接回滚
            if ((!isAutoCommit) && (!isReadOnly)) {
                pooledConnection.rollback();
            }

            // reset holder, restore default settings, clear warnings
            boolean isSameThread = pooledConnection.ownerThread == Thread.currentThread();
            if (!isSameThread) { //同样判断线程,为了保证安全性
                final ReentrantLock lock = pooledConnection.lock;
                lock.lock();
                try {
                    holder.reset(); //连接被借出去后,可能被业务方改动了一些属性(典型的比如autoCommit),现在利用reset方法还原为默认值
                } finally {
                    lock.unlock();
                }
            } else {
                holder.reset(); //同上,这里认为获取和关闭连接的是同一个线程,不存在线程安全问题,因此不用去竞争锁
            }

            //连接已被抛弃,则不作任何处理(不再归还)
            if (holder.discard) {
                return;
            }

            //忽略
            if (phyMaxUseCount > 0 && holder.useCount >= phyMaxUseCount) {
                discardConnection(holder.conn);
                return;
            }

            //如果驱动连接本身被人为关闭了,除一些监控值之外,也不做处理
            if (physicalConnection.isClosed()) {
                lock.lock();
                try {
                    activeCount--;
                    closeCount++;
                } finally {
                    lock.unlock();
                }
                return;
            }

            //参考testOnBorrow,这里testOnReturn就是指每次回收连接都要做连接可用性检查,同样官方不建议开启,影响性能,缺省值也是不开启的
            if (testOnReturn) {
                //流程忽略
                boolean validate = testConnectionInternal(holder, physicalConnection);
                if (!validate) {
                    JdbcUtils.close(physicalConnection);

                    destroyCountUpdater.incrementAndGet(this);

                    lock.lock();
                    try {
                        activeCount--;
                        closeCount++;
                    } finally {
                        lock.unlock();
                    }
                    return;
                }
            }

            if (!enable) {
                //中途发现连接又被置为不可用,则直接触发抛弃方法,参考流程1.4和代码段1-5
                discardConnection(holder.conn);
                return;
            }

            boolean result;
            final long currentTimeMillis = System.currentTimeMillis();

            if (phyTimeoutMillis > 0) {
                long phyConnectTimeMillis = currentTimeMillis - holder.connectTimeMillis;
                if (phyConnectTimeMillis > phyTimeoutMillis) {
                    discardConnection(holder.conn);
                    return;
                }
            }

            lock.lock();
            try {
                activeCount--;
                closeCount++;

                //最终放入池子,方法详情在下方
                result = putLast(holder, currentTimeMillis);
                recycleCount++;
            } finally {
                lock.unlock();
            }

            if (!result) { //如果加不进去,则直接关闭驱动连接,然后不处理(此时holder已经失去强引用,不久便会被回收)
                JdbcUtils.close(holder.conn);
                LOG.info("connection recyle failed.");
            }
        } catch (Throwable e) {
            holder.clearStatementCache();

            if (!holder.discard) {
                this.discardConnection(physicalConnection);
                holder.discard = true;
            }

            LOG.error("recyle error", e);
            recycleErrorCountUpdater.incrementAndGet(this);
        }
    }

    //DruidDataSource类里的putLast方法,由上方的recycle方法触发
    boolean putLast(DruidConnectionHolder e, long lastActiveTimeMillis) {
        if (poolingCount >= maxActive) { //池子已满,不加
            return false;
        }

        e.lastActiveTimeMillis = lastActiveTimeMillis; //刷新上次活跃时间,该时间很重要,直接影响连接检查的触发
        connections[poolingCount] = e; //放进连接池数组尾部
        incrementPoolingCount(); //poolingCount++

        if (poolingCount > poolingPeak) {
            poolingPeak = poolingCount;
            poolingPeakTime = lastActiveTimeMillis;
        }

        notEmpty.signal(); //因为成功回收了一个连接,那就唤起一次所有因为获取不到连接而被阻塞的业务线程吧~(参考流程1.2)
        notEmptySignalCount++;

        return true;
    }

posted @ 2019-09-22 12:31  是胖虎捏  阅读(738)  评论(0编辑  收藏  举报