当前位置: 首页 > 知识库问答 >
问题:

在Tomcat中启用Context reload="true"时,JDBC连接池将耗尽连接

子车高超
2023-03-14

我正在EclipseJuno中开发一个JavaEEWeb应用程序。我已经将Tomcat配置为使用JDBC连接池(org.apache.Tomcat.JDBC.pool)和PostgreSQL数据库。以下是我的项目META-INF/context中的配置。xml:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <!-- Configuration for the Tomcat JDBC Connection Pool -->
    <Resource name="jdbc/someDB"
        type="javax.sql.DataSource"
        auth="Container"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="org.postgresql.Driver"
        url="jdbc:postgresql://localhost:5432/somedb"
        username="postgres"
        password="12345"
        maxActive="100"
        minIdle="10"
        initialSize="10"
        validationQuery="SELECT 1"
        validationInterval="30000"
        removeAbandoned="true"
        removeAbandonedTimeout="60"
        abandonWhenPercentageFull="50" />
</Context>

我的应用程序使用Eclipse部署到Tomcat,在Tomcat的context.xml属性reloadable设置为"true",以便在检测到更改时自动重新加载Web应用程序:

我注意到,每次发生上述自动重新加载时,都会保留10个到PostgreSQL db的连接(因为在webapp的context.xml initialSize=“10”中)。因此,在10次更改后,将引发PSQLException:

org.postgresql.util.PSQLException: FATAL: sorry, too many clients already
...

如果我手动重启Tomcat-一切都很好,只有10个连接被保留。

有人知道解决这个问题的方法吗?这样就有可能在reloadable设置为“true”的情况下开发,而不会在每次重新加载上下文时导致连接池增加?

非常感谢您的帮助。

另外,ApacheTomcat版本7.0。32


共有1个答案

荀辰钊
2023-03-14

为了解决这个问题,在上下文中向资源元素添加一个值为“close”的属性closeMethod(这里有文档记录)。xml文件。

以下是我 /META-INF/context.xml文件的正确内容:

<Context>
    <!-- Configuration for the Tomcat JDBC Connection Pool -->
    <Resource name="jdbc/someDB"
        type="javax.sql.DataSource"
        auth="Container"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="org.postgresql.Driver"
        url="jdbc:postgresql://localhost:5432/somedb"
        username="postgres"
        password="12345"
        maxActive="100"
        minIdle="10"
        initialSize="10"
        validationQuery="SELECT 1"
        validationInterval="30000"
        removeAbandoned="true"
        removeAbandonedTimeout="60"
        abandonWhenPercentageFull="50"
        closeMethod="close" />
</Context>

注意属性关闭方法。我对它进行了测试,现在连接的数量严格按照上下文中的定义保持。xml文件!

注意
有一个时刻(与JNDI有关)可以处理。有关完整描述,请参阅UPDATE 3。

好的,多亏了ApacheTomcat委员会的康斯坦丁·科林科,我找到了上述解决方案。我在ASF Bugzilla和

更新1(2012-12-03)又名“新希望”===

嗯,结果还是一只虫子。ApacheTomcat7发布经理MarkThomas确认(引用):

“这是jdbc池中的内存泄漏错误。PoolCleaner实例正在保留对ConnectionPool的引用,以防止其被GC读取。

这已在trunk和7.0.x中修复,并将包含在7.0.34以后的版本中。”

因此,如果您有较旧的Tomcat版本(小于7.0.34),请使用上述解决方案,否则, <罢工> 从Apache Tomcat版本7.0.34开始,不应该有像我描述的问题。 (见更新2)

===更新2 (2014-01-13)又名“问题反击”===

即使对于当前最新的ApacheTomcat版本7.0,我的错误报告中最初描述的问题似乎仍然存在。我还用Tomcat7.0复制了它。47(感谢Miklos Krivan指出这一点)。虽然现在Tomcat有时会在重新加载后关闭额外的连接,有时在重新加载后连接数会增加,然后保持稳定,但最终这种行为仍然不可靠。

我仍然可以重现最初描述的问题(尽管也不是那么容易:它可能与连续重新加载的频率有关)。这似乎只是时间问题,也就是说,如果Tomcat在重新加载后有足够的时间,它会或多或少地管理连接池。正如MarkThomas在他的评论(引文)中提到的:“根据closeMethod的文档,该方法的存在只是为了加速释放GC本来可以释放的资源。”(引用结束),看起来速度是决定性因素。

当使用Konstantin Kolinko(使用closeMethod=“close”)提供的解决方案时,一切正常,保留的连接数严格按照上下文中的定义保持。xml文件。因此,使用closeMethod=“close”似乎是(目前)避免在重新加载上下文后耗尽连接的唯一正确方法。

===UPDATE3 (2014-01-13)又名"Tomcat版本管理器的返回"===

更新2中描述的行为背后的谜团已经解开。在我收到MarkThomas(Tomcat发布经理)的回复后,更多的细节已经澄清。我希望这是最后一次更新。因此,正如更新1中提到的,这个bug确实已经修复了。我将马克回复中的重要部分作为引用(我的重点):

根据评论#4到#6,在调查此错误时发现的实际内存泄漏已在7.0.34中修复。

重载时连接未关闭的问题是JNDI资源的J2EE规范的结果,因此错误报告的这一部分是无效的。我将此错误的状态恢复为修复,以反映内存泄漏已经修复。

为了进一步说明重新加载后立即关闭连接失败无效的原因,J2EE规范没有为容器提供机制来告诉资源不再需要它。因此,容器所能做的就是清除对资源的引用并等待垃圾回收(这将触发池和相关连接的关闭)。垃圾收集在JVM确定的时间发生,这就是为什么在上下文重新加载后关闭连接需要不确定的时间,因为垃圾收集可能在一段时间内不会发生。

Tomcat添加了Tomcat特定的JNDI属性Closemethod,该属性可用于在上下文停止时触发JNDI资源的显式关闭。如果不能接受等待GC清理资源,则只需使用此参数。默认情况下,Tomcat不会使用此选项,因为它可能会对某些JNDI资源产生意外和不必要的副作用。

如果您希望看到提供一种标准机制来告诉JNDI资源不再需要它们,那么您需要游说J2EE专家组。

只需使用本文开头介绍的解决方案(但是,为了以防万一,请记住使用它在理论上可能会产生JNDI相关的问题)。

MichaelOsipov建议使用他的CloseableResourceListener,它可以防止在取消部署web应用程序期间由左打开的资源导致的内存泄漏。所以你也可以试试看。

免责声明
更新的别名是受星球大战系列电影的启发。所有权利属于各自的所有者。

 类似资料:
  • 问题内容: 我正在Eclipse Juno中开发JavaEEWeb应用程序。我已将Tomcat配置为与PostgreSQL数据库一起使用JDBC连接池(org.apache.tomcat.jdbc.pool)。这是我的项目的META-INF / context.xml中的配置: 我的应用程序是使用Eclipse部署到Tomcat的,并且在Tomcat的context.xml中,可重载属性设置为“

  • 我在项目中使用ApacheTomcat JDBC连接池。我很困惑,因为在重负下,我一直看到以下错误: 我的期望是,使用池,新连接的请求将被保留在队列中,直到连接可用。相反,当池达到容量时,请求似乎会被拒绝。这种行为可以改变吗? 谢谢, 达尔 这是我的池配置:

  • 我正在Eclipse Juno中开发一个Java EE web应用程序。我已经将Tomcat配置为使用JDBC连接池(org.apache.Tomcat.JDBC.pool)和PostgreSQL数据库。以下是我项目的META-INF/context.xml中的配置: 我的应用程序使用Eclipse部署到Tomcat,在Tomcat的context.xml中,一个属性reloadable被设置为“

  • 问题内容: 我在GlassFish上有一个Java-JSF Web应用程序,我想在其中使用连接池。因此,我创建了一个有范围的Bean,可与其他Bean的实例一起使用: 这样,连接池很快就会被填满。在“ db-related”视图中进行几次导航后,应用程序将停止以下操作: RAR5117:无法从连接池[mysql_testPool]获取/创建连接。原因:使用中的连接等于最大池大小和已过期的最大等待时

  • 我有使用hikari池创建连接池的Spring启动应用程序。我们正在使用postgres sql用于db。当我以低qps命中系统时,请求需要大约200毫秒来执行。当部署一个pod并且qps为15时,事情保持良好状态。但是一旦我将qps增加到20,请求就开始需要大约10秒来处理,连接池变空(java.sql.SQLTransientConntion异常:菲尼克斯-连接不可用,请求在30183毫秒后超

  • null null 额外信息:没有其他异常抛出,我知道。所有其他数据都被正确地检索。派人帮忙。 更新:我做了一些更多的实验:这个应用程序使用了另一个dao,我之前没有提到,因为我忘了。它的工作方式几乎相同,只是连接到一个不同的数据库,所以它有一个单独的配置。它还利用了JdbcNamedTemplate和@Qualifier来选择正确的模板。 现在,我发现,使一个或另一个DAO失效将不再吃连接。所以