JBoss中数据库连接泄漏疑问:未关闭连接为何返回连接池?
我的Java Spring Boot只读应用(无写入操作)中,很多方法未关闭数据库连接。部署至JBoss后,我在standalone.xml里配置了CCM及数据库连接日志:
<logger category="org.jboss.jca"> <level name="DEBUG"/> </logger> <cached-connection-manager debug="true" error="true"/>
日志中出现数据库连接泄漏提示:
14:44:59,620 INFO [org.jboss.jca.core.api.connectionmanager.ccm.CachedConnectionManager] (default task-19) IJ000100: Closing a connection for you. Please close them yourself: org.jboss.jca.adapters.jdbc.jdk8.WrappedConnectionJDK8@2e62903a: java.lang.Throwable: STACKTRACE at org.jboss.jca.core.connectionmanager.ccm.CachedConnectionManagerImpl.registerConnection(CachedConnectionManagerImpl.java:308) at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:819) at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:151) at org.jboss.as.connector.subsystems.datasources.WildFlyDataSource.getConnection(WildFlyDataSource.java:64) ... at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280) at java.lang.Thread.run(Thread.java:748) Caused by: javax.resource.ResourceException: IJ000151: Some connections were not closed, see the log for the allocation stacktraces at org.jboss.jca.core.connectionmanager.ccm.CachedConnectionManagerImpl.popMetaAwareObject(CachedConnectionManagerImpl.java:289) at org.jboss.as.connector.deployers.ra.processors.CachedConnectionManagerSetupProcessor$CachedConnectionManagerSetupAction.teardown(CachedConnectionManagerSetupProcessor.java:116) ... 13 more
但查看getConnection和returnConnection日志时,显示活跃连接为0(格式[0/100]中,总连接数为100):
返回连接日志:
15:27:42,366 DEBUG [org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory] (default task-25) java.sql.Connection#endRequest has been invoked 15:27:42,366 DEBUG [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] (default task-25) XXDB: returnConnection(557f1b10, false) [0/100]
移除空闲连接日志:
15:27:40,833 DEBUG [org.jboss.jca.core.connectionmanager.pool.idle.IdleRemover] (IdleRemover) Notifying pools, interval: 60000 15:27:40,833 DEBUG [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] (IdleRemover) XXDB: removeIdleConnections(1708269940833) [0/100]
获取连接日志:
15:27:41,448 DEBUG [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] (default task-25) XXDB: getConnection(null, WrappedConnectionRequestInfo@5e9a45d6[userName=xxxxxx]) [0/100]
我有两个疑问:
- 若活跃连接为0,是否意味着连接已返回连接池?我的理解是否正确?
- 若代码未关闭连接且日志显示连接泄漏,连接为何仍能返回连接池?
问题1:活跃连接为0是否代表连接已返回连接池?
你的理解基本正确。日志里的[0/100]格式中,第一个数字就是当前被业务线程持有、未归还到池中的活跃连接数。当数值为0时,说明连接池内所有连接都处于空闲状态,没有被线程占用,也就是所有连接都已回到连接池。
需要注意的是:这个数值是日志打印瞬间的状态,如果代码存在连接泄漏,但泄漏的连接刚好在日志打印前被JBoss的CCM自动回收,也会出现活跃连接为0的情况——这正好匹配你遇到的场景。
问题2:代码未关连接但连接仍能返回池的原因
这完全是因为你配置的JBoss CCM(Cached Connection Manager)在起作用。你在standalone.xml中设置的<cached-connection-manager debug="true" error="true"/>,核心功能就是监控线程与连接的绑定关系:当线程执行结束(比如请求处理完成)时,CCM会检查该线程是否存在未关闭的数据库连接,若有则自动帮你关闭连接并归还到连接池,同时打印你看到的IJ000100警告日志。
简单来说:你代码里没手动关闭连接,但JBoss的CCM在线程生命周期结束时替你完成了收尾操作,把连接还回了池里,所以日志会同时出现“连接泄漏警告”和“活跃连接为0”的情况。
不过要明确:CCM只是兜底机制,不能替代代码中正确关闭连接的操作。高并发场景下,若CCM还没来得及回收泄漏的连接,新请求又占用新连接,可能导致连接池短暂耗尽;频繁的自动回收也会带来额外性能开销。正确的做法是在代码中使用try-with-resources语法,或者手动调用conn.close()关闭连接。
内容的提问来源于stack exchange,提问作者Coder

