当前位置: 首页 > 面试题库 >

在Tomcat中启用Context reload =“ true”时,JDBC连接池用尽了连接

田马鲁
2023-03-14
问题内容

我正在Eclipse Juno中开发JavaEEWeb应用程序。我已将Tomcat配置为与PostgreSQL数据库一起使用JDBC连接池(org.apache.tomcat.jdbc.pool)。这是我的项目的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中,可重载属性设置为“
true”,以便在检测到更改时自动重载该Web应用程序:

<Context reloadable="true">

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

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

如果我手动重启Tomcat-一切正常,并且仅保留10个连接。

有谁知道解决此问题的方法,因此可以将reloadable设置为“ true”进行开发,而不会在每次重新加载上下文时导致池化更多的连接吗?

将不胜感激。

PS Apache Tomcat版本7.0.32


问题答案:

为了解决此问题,请在context.xml文件中的 Resource 元素中添加一个值为“ close
的属性closeMethod(在此处记录)。

这是我的/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>

注意属性 closeMethod 。我对其进行了测试,现在连接的数量严格按照 context.xml 文件中的定义保持!

注意可能
有一个时刻(与JNDI相关)。有关完整说明,请参见UPDATE 3。

长答案

好的,感谢Apache Tomcat提交者KonstantinKolinko,我找到了上述解决方案。我将此问题报告为ASF
Bugzilla上的Apache Tomcat错误, 事实证明这不是错误 (请参阅UPDATE 1)。

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

好吧,事实证明那仍然是一个 错误 。Apache Tomcat 7版本管理器Mark Thomas
确认(引用):

“这是jdbc-pool中的内存泄漏错误。PoolCleaner实例保留了对ConnectionPool的引用,从而防止了它被GC损坏
。…
这已在trunk和7.0.x中修复,并将在7.0.34及以后版本中包含。 。”

因此,如果您拥有较旧的Tomcat版本(低于7.0.34),请使用上述解决方案,否则, 从Apache Tomcat
7.0.34版开始,应该不会出现我所描述的问题。
(请参阅更新2)

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

即使对于当前最新的Apache Tomcat
7.0.50版,似乎仍然存在我的错误报告中最初描述的问题,并且我还使用Tomcat
7.0.47复制了该问题)。尽管现在Tomcat有时会在重新加载后设法关闭其他连接,有时在一次重新加载后会增加连接数量,然后保持稳定,但是最终这种行为仍然不可靠。

我仍然可以重现
最初描述的问题(尽管同样不那么容易:它可能与连续重新加载的频率有关)。似乎只是时间问题,即,如果Tomcat在重新加载后有足够的时间,它将或多或少地管理连接池。正如马克·托马斯(Mark
Thomas)在他的评论(引号)中所提到的:“根据closeMethod的文档,该方法仅用于加快资源的释放,而这些资源本来可以由GC释放的。”
(报价结尾),速度似乎是决定性因素。

使用Konstantin Kolinko提出的解决方案(使用closeMethod=“close”)时,所有工作都很好,并且保留的连接数严格按照context.xml文件中的定义进行。因此看来,使用closeMethod =“close”是目前唯一避免在重新加载上下文后用尽连接的正确方法。

=== 更新3(2014-01-13)又名“返回Tomcat版本管理器” ===

解决了UPDATE 2中描述的行为背后的谜团。在收到Mark
Thomas(Tomcat版本管理器)的答复后,现在已经清除了更多详细信息。我希望这是最后更新。因此,该错误
的确得到了修复, 如UPDATE 1所述。我在此处将Mark的答复的重要部分作为引号(强调我的)发布:

调查此错误时发现的实际内存泄漏已在7.0.34及更高版本中按注释4至6修复。

连接问题在重新加载时未关闭是JNEE资源的J2EE规范的结果,因此,错误报告的此部分无效。我正在修复此错误的状态,以反映确实存在的内存泄漏已得到修复。

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

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

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

结论

只需使用本文开头提供的解决方案即可(但以防万一,请记住,从 理论上讲 ,使用它可能引起与JNDI相关的问题)。

替代解决方案

MichaelOsipov建议使用他的_CloseableResourceListener_](http://mo-tomcat-ext.sourceforge.net/user-guide.html#CloseableResourceListener)
,它可以防止在取消部署Web应用程序期间由于打开的资源导致的内存泄漏。因此,您也可以尝试一下。

免责声明 UPDATES的别名来自《星球大战》电影系列。所有权利均属于其各自所有者。



 类似资料:
  • 我正在EclipseJuno中开发一个JavaEEWeb应用程序。我已经将Tomcat配置为使用JDBC连接池(org.apache.Tomcat.JDBC.pool)和PostgreSQL数据库。以下是我的项目META-INF/context中的配置。xml: 我的应用程序使用Eclipse部署到Tomcat,在Tomcat的context.xml属性reloadable设置为"true",以便

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

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

  • 我们刚刚从dbcp迁移到tomcat jdbc连池。我们在加载中尝试了系统,收到了以下异常: 请注意: 不忙的连接在哪里?忙的数字在这之后一直在下降,但我们仍然没有得到任何连接。 有什么想法吗? 配置: env:ubuntu和tomcat 6. db-mysql

  • 我们有一个spring-boot应用程序,它使用嵌入式tomcat进行部署,并使用MySQL后端的默认tomcat-jdbc连接池,而没有为MySQL或tomcat端定制。 该应用程序有一些调度程序,它们主要在一天中的特定时间运行,即在昨天的最后一次cron运行和今天的第一次cron运行之间,有超过9个小时的间隙。然而,无论何时cron在早期运行,它都从未遇到过空闲连接问题。 现在我们看到一条错误

  • Tomcat在使用后不释放连接的原因可能是什么? 这是我的配置