Alibaba Druid 源码阅读(五)数据库连接池 连接关闭探索
 作者:萧
- 2021 年 11 月 12 日
- 本文字数:4052 字 - 阅读完需:约 13 分钟 
简介
在上文中探索了数据库连接池的获取,下面接着初步来探索下数据库连接的关闭,看看其中具体执行了那些操作
连接关闭
下面的具体的代码,相关的位置,加上了自己的注释:
    @Override    public void close() throws SQLException {        // 下面两段检查避免重复关闭        if (this.disable) {            return;        }
        DruidConnectionHolder holder = this.holder;        if (holder == null) {            if (dupCloseLogEnable) {                LOG.error("dup close");            }            return;        }
        // 判断是否是一样的线程,不是则使用异步关闭        DruidAbstractDataSource dataSource = holder.getDataSource();        boolean isSameThread = this.getOwnerThread() == Thread.currentThread();
        if (!isSameThread) {            dataSource.setAsyncCloseConnectionEnable(true);        }
        if (dataSource.isAsyncCloseConnectionEnable()) {            syncClose();            return;        }
        if (!CLOSING_UPDATER.compareAndSet(this, 0, 1)) {            return;        }
        try {            // 连接关闭时的一些增强?            for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {                listener.connectionClosed(new ConnectionEvent(this));            }
            // Filter也能作用到连接关闭时?            List<Filter> filters = dataSource.getProxyFilters();            if (filters.size() > 0) {                FilterChainImpl filterChain = new FilterChainImpl(dataSource);                filterChain.dataSource_recycle(this);            } else {                recycle();            }        } finally {            CLOSING_UPDATER.set(this, 0);        }
        this.disable = true;    }
        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) {            DruidAbstractDataSource dataSource = holder.getDataSource();            dataSource.recycle(this);        }
        this.holder = null;        conn = null;        transactionInfo = null;        closed = true;    }
复制代码
 下面是具体的 recycle()函数内容:
    /**     * 回收连接     */    protected void recycle(DruidPooledConnection pooledConnection) throws SQLException {        final DruidConnectionHolder holder = pooledConnection.holder;
        if (holder == null) {            LOG.warn("connectionHolder is null");            return;        }
        // 一个warn,并没有直接返回        if (logDifferentThread //            && (!isAsyncCloseConnectionEnable()) //            && pooledConnection.ownerThread != Thread.currentThread()//        ) {            LOG.warn("get/close not same thread");        }
        final Connection physicalConnection = holder.conn;
        // 使用双重检查锁,将traceEnable,目前尚不清楚其具体作用        if (pooledConnection.traceEnable) {            Object oldInfo = null;            activeConnectionLock.lock();            try {                if (pooledConnection.traceEnable) {                    oldInfo = activeConnections.remove(pooledConnection);                    pooledConnection.traceEnable = 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 {            // check need to rollback?            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();                } finally {                    lock.unlock();                }            } else {                holder.reset();            }
            if (holder.discard) {                return;            }
            // 如果计数标识大于配置的最大数,则关闭连接            if (phyMaxUseCount > 0 && holder.useCount >= phyMaxUseCount) {                // 关闭了连接                // 同时如果活跃连接数小于配置的最小活跃数,会发送通知(具体作用后面再查看)                discardConnection(holder);                return;            }
            // 计数标识设置            if (physicalConnection.isClosed()) {                lock.lock();                try {                    if (holder.active) {                        activeCount--;                        holder.active = false;                    }                    closeCount++;                } finally {                    lock.unlock();                }                return;            }
            // 检测连接是否还有效,无效则返还,并设置计数标识位            if (testOnReturn) {                boolean validate = testConnectionInternal(holder, physicalConnection);                if (!validate) {                    JdbcUtils.close(physicalConnection);
                    destroyCountUpdater.incrementAndGet(this);
                    lock.lock();                    try {                        if (holder.active) {                            activeCount--;                            holder.active = false;                        }                        closeCount++;                    } finally {                        lock.unlock();                    }                    return;                }            }            if (holder.initSchema != null) {                holder.conn.setSchema(holder.initSchema);                holder.initSchema = null;            }
            // 这里又关闭了一次连接            // 在非enable的情况下            if (!enable) {                discardConnection(holder);                return;            }
            boolean result;            final long currentTimeMillis = System.currentTimeMillis();
            // 连接超时关闭?这个超时具体是指什么还没搞清楚            if (phyTimeoutMillis > 0) {                long phyConnectTimeMillis = currentTimeMillis - holder.connectTimeMillis;                if (phyConnectTimeMillis > phyTimeoutMillis) {                    discardConnection(holder);                    return;                }            }
            // 设置计数标识,同时没有关闭连接,而是放入池中            lock.lock();            try {                if (holder.active) {                    activeCount--;                    holder.active = false;                }                closeCount++;
                result = putLast(holder, currentTimeMillis);                recycleCount++;            } finally {                lock.unlock();            }
            if (!result) {                JdbcUtils.close(holder.conn);                LOG.info("connection recyle failed.");            }        } catch (Throwable e) {            // 异常情况下关闭连接            holder.clearStatementCache();
            if (!holder.discard) {                discardConnection(holder);                holder.discard = true;            }
            LOG.error("recyle error", e);            recycleErrorCountUpdater.incrementAndGet(this);        }    }
复制代码
 总结
通过上面代码可以看出:
- 1.Close 做了同步和异步关闭之类的检查,但 AsyncClose 和 recycle 没有有比较大的区别,似乎也不是新开的线程去回收连接,看着似乎也是走的同步,这个目前对 async 的异步函数有点疑惑 
- 2.在回收连接的处理中,如果超过一定的条件限制,就会关闭连接;其他就会放回到连接池中 
划线
评论
复制
发布于: 2 小时前阅读数: 4
版权声明: 本文为 InfoQ 作者【萧】的原创文章。
原文链接:【http://xie.infoq.cn/article/82ad2135f17d15cc9c97acaa3】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。

萧
关注
还未添加个人签名 2018.09.09 加入
代码是门手艺活,也是门艺术活











 
    
评论