乐趣区

关于druid:聊聊druid的return行为

本文次要钻研一下 druid 的 return 行为

close

com/alibaba/druid/pool/DruidPooledConnection.java

    @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));
            }

            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;
    }

close 办法先从 holder 获取以后的 dataSource,而后判断 ownerThread,若不是同一个线程则设置 asyncCloseConnectionEnable 为 true,若 asyncCloseConnectionEnable 为 true 则执行 syncClose( 这里语义貌似相同 ),否则执行 recycle 办法

syncClose

com/alibaba/druid/pool/DruidPooledConnection.java

    public void syncClose() throws SQLException {lock.lock();
        try {if (this.disable || CLOSING_UPDATER.get(this) != 0) {return;}

            DruidConnectionHolder holder = this.holder;
            if (holder == null) {if (dupCloseLogEnable) {LOG.error("dup close");
                }
                return;
            }

            if (!CLOSING_UPDATER.compareAndSet(this, 0, 1)) {return;}

            for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {listener.connectionClosed(new ConnectionEvent(this));
            }

            DruidAbstractDataSource dataSource = holder.getDataSource();
            List<Filter> filters = dataSource.getProxyFilters();
            if (filters.size() > 0) {FilterChainImpl filterChain = new FilterChainImpl(dataSource);
                filterChain.dataSource_recycle(this);
            } else {recycle();
            }

            this.disable = true;
        } finally {CLOSING_UPDATER.set(this, 0);
            lock.unlock();}
    }

syncClose 办法次要是加锁执行 recycle

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) {DruidAbstractDataSource dataSource = holder.getDataSource();
            dataSource.recycle(this);
        }

        this.holder = null;
        conn = null;
        transactionInfo = null;
        closed = true;
    }

recycle 办法次要是执行 dataSource.recycle(this)

DruidDataSource.recycle

com/alibaba/druid/pool/DruidDataSource.java

    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) {
            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;
            }

            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);
        }
    }

    boolean putLast(DruidConnectionHolder e, long lastActiveTimeMillis) {if (poolingCount >= maxActive || e.discard || this.closed) {return false;}

        e.lastActiveTimeMillis = lastActiveTimeMillis;
        connections[poolingCount] = e;
        incrementPoolingCount();

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

        notEmpty.signal();
        notEmptySignalCount++;

        return true;
    }

recycle 办法先执行 DruidConnectionHolder 的 reset 办法,之后针对大于等于 phyMaxUseCount 的场景执行 discardConnection;针对 testOnReturn 为 true,则执行 testConnectionInternal 校验,校验失败则敞开连贯;最初加锁执行 putLast 把连贯放回连接池,若偿还失败则敞开连贯。

小结

close 办法先从 holder 获取以后的 dataSource,而后判断 ownerThread,若不是同一个线程则设置 asyncCloseConnectionEnable 为 true,若 asyncCloseConnectionEnable 为 true 则执行 syncClose( 这里语义貌似相同 ),否则执行 recycle 办法。

退出移动版