1.官方解释
当程序存在缺陷时,申请的连接忘记关闭,这时候,就存在连接泄漏了。Druid提供了RemoveAbandanded相关配置,用来关闭长时间不使用的连接。RemoveAbandanded功能不建议在生产环境中使用,仅用于连接泄露检测诊断
参数 | 说明 |
---|---|
removeAbandoned | 如果连接泄露,是否需要回收泄露的连接,默认false; |
logAbandoned | 如果回收了泄露的连接,是否要打印一条log,默认false; |
removeAbandonedTimeoutMillis | 连接回收的超时时间,默认5分钟; |
https://github.com/alibaba/druid/wiki/%E8%BF%9E%E6%8E%A5%E6%B3%84%E6%BC%8F%E7%9B%91%E6%B5%8B
2.Druid的1.2.9_preview_01源码,你如果没有配置destroyScheduler,除非你手动调用removeAbandoned(),不然加了配置也没用,调用这个方法,是连接创建到现在的时间如果大于
removeAbandonedTimeoutMillis,就会把活跃连接直接关闭了;不过要注意只有的连接的disable为false才会把会把活跃连接直接关闭掉,不然跳过
protected void createAndStartDestroyThread() { destroyTask = new DestroyTask(); if (destroyScheduler != null) { long period = timeBetweenEvictionRunsMillis; if (period <= 0) { period = 1000; } destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period, TimeUnit.MILLISECONDS); initedLatch.countDown(); return; } String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this); destroyConnectionThread = new DestroyConnectionThread(threadName); destroyConnectionThread.start(); } public class DestroyTask implements Runnable { public DestroyTask() { } @Override public void run() { shrink(true, keepAlive); if (isRemoveAbandoned()) { removeAbandoned(); } } }
public int removeAbandoned() { int removeCount = 0; long currrentNanos = System.nanoTime(); List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>(); activeConnectionLock.lock(); try { Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator(); for (; iter.hasNext();) { DruidPooledConnection pooledConnection = iter.next(); if (pooledConnection.isRunning()) { continue; } long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000); if (timeMillis >= removeAbandonedTimeoutMillis) { iter.remove(); pooledConnection.setTraceEnable(false); abandonedList.add(pooledConnection); } } } finally { activeConnectionLock.unlock(); } if (abandonedList.size() > 0) { for (DruidPooledConnection pooledConnection : abandonedList) { final ReentrantLock lock = pooledConnection.lock; lock.lock(); try { if (pooledConnection.isDisable()) { continue; } } finally { lock.unlock(); } JdbcUtils.close(pooledConnection); pooledConnection.abandond(); removeAbandonedCount++; removeCount++; if (isLogAbandoned()) { StringBuilder buf = new StringBuilder(); buf.append("abandon connection, owner thread: "); buf.append(pooledConnection.getOwnerThread().getName()); buf.append(", connected at : "); buf.append(pooledConnection.getConnectedTimeMillis()); buf.append(", open stackTrace\n"); StackTraceElement[] trace = pooledConnection.getConnectStackTrace(); for (int i = 0; i < trace.length; i++) { buf.append("\tat "); buf.append(trace[i].toString()); buf.append("\n"); } buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState() + ", current stackTrace\n"); trace = pooledConnection.getOwnerThread().getStackTrace(); for (int i = 0; i < trace.length; i++) { buf.append("\tat "); buf.append(trace[i].toString()); buf.append("\n"); } LOG.error(buf.toString()); } } } return removeCount; }
3.disable属性表示连接是不是被禁用,DruidDataSource.handleFatalError()和DruidPooledConnection.close()方法会把这个属性置为true,而且DruidPooledXAConnection.close()调用了DruidPooledConnection.close()方法;
DruidPooledConnection.close()和DruidDataSource.removeAbandoned()会根据这个属性去判断要不要关闭连接,其他地方都没用到这个属性,当下还不知道这个的作用在哪里
DruidPooledConnection.close方法
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!