我正在开发在Eclipse朱诺在Java EE Web应用程序。 我已经配置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中的属性重新加载设置为“真”如果检测到变化,自动重新加载web应用程序:
<Context reloadable="true">
我注意到,每次上述的自动重新加载是发生到PostgreSQL分贝10个更多的连接时被保留(因为在web应用程序的context.xml中INITIALSIZE =“10”)。 所以,10后改变一个PSQLException抛出:
org.postgresql.util.PSQLException: FATAL: sorry, too many clients already
...
如果我手动重新启动Tomcat - 一切都很好,只是10个连接被保留。
有谁知道解决这个问题的方式,所以它可能是可能的重新装入集发展到“真”,而不是导致每次的背景下被重新加载时间汇集更多的连接?
希望得到任何帮助。
PS的Apache Tomcat版本7.0.32
将该溶液(TL; DR)
为了解决这个问题,添加属性closeMethod
(记录在这里与值在context.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>
注意属性closeMethod。 我测试了它和现在的连接数都严格保持在context.xml文件中定义!
注意
有一个时刻(有关JNDI)可能采取的照顾。 请参阅更新3的完整描述。
长一点的回答
好吧,我发现了上述解决方案的感谢到Apache Tomcat committor 康斯坦丁Kolinko 。 我报道这个问题上ASF Bugzilla的一个Apache Tomcat错误和事实证明这不是一个bug(见更新1)。
=== 更新1(2012年12月3日),又名“新希望” ===
那么,它仍然被证明是一个错误 。 马克托马斯 ,是Apache Tomcat 7的发布经理, 证实那(报价):
“这是在JDBC池内存泄露问题。PoolCleaner实例保留到连接池引用防止它被GC'd。
...
这已被固定在躯干和的7.0.x和将包含在7.0.34开始。”
所以,如果你有一个旧版本的Tomcat(小于7.0.34),使用上面的解决方案,否则, 开始的Apache Tomcat版本7.0.34,也应该像我描述了一个没有问题。 (见UPDATE 2)
=== 更新2(2014年1月13日),又名“问题反击” ===
这似乎是在最初描述的问题我的错误报告仍然存在,即使是目前最新的Apache Tomcat版本7.0.50,我也和Tomcat 7.0.47(感谢转载它米克洛什Krivan指点出来)。 虽然现在有时,Tomcat管理重装后关闭额外的连接,有时连接的数量是一个重装后上升后保持稳定,但最终这种行为仍然是不可靠的。
我仍然可以重现最初描述的问题(虽然也不那么容易:它可能与连续重载的频率)。 好像这只是一个时间的问题,即如果Tomcat重装后有足够的时间,它管理的连接池或多或少因为它应该。 正如马克·托马斯在他提到的评论 (引号):“按照该文档为closeMethod,该方法只存在加快,否则将通过GC来释放资源的释放。” (引用的结束)时,它看起来像速度的决定性因素。
当使用由康斯坦丁Kolinko提出的解决方案(使用closeMethod =“关闭”)一切工作得很好,并且保留的连接的数量是严格保持为在context.xml文件定义。 所以看来使用closeMethod =“亲密”是唯一正确的方法(目前),以避免情况下重装后所剩无几的连接。
=== 更新3(2014年1月13日),又名“Tomcat的发行经理归来” ===
后面的UPDATE 2所描述的行为谜团解开。 我收到后的更多细节已经现已清除答复马克·托马斯(Tomcat的发行经理)。 我希望这是最后一次更新。 因此,错误确实固定为在更新1.我张贴马克的答复这里报价(重点煤矿)的重要组成部分提到:
实际的内存泄漏发现在调查这个bug已被固定在7.0.34起按评论#4至#6。
没有被重新加载关闭连接的问题是JNDI资源J2EE规范的结果和错误报告的这部分因此是无效的。 我恢复了这个bug的状态固定,以反映该确实存在内存泄漏已得到修复。
为了扩大为什么不立即关闭连接后重装无效,J2EE规范没有提供机制的容器来告诉它不再需要的资源。 因此,所有的容器可以做的是资源的明确引用,并等待垃圾回收(这将触发池的关闭和相关的连接)。 垃圾收集发生在由JVM确定的时间,所以这是为什么需要不确定的时间量用于上下文重载作为垃圾收集可能不会在一段时间后发生要被关闭的连接 。
Tomcat的添加了特定于Tomcat的JNDI属性closeMethod可以用来当上下文停止触发JNDI资源的显式关闭。 如果等待GC清理资源是不能接受的则只需使用此参数 。 Tomcat作为它可能有一些JNDI资源意外和不必要的副作用默认不使用此功能。
如果你想看到提供告知,他们不再需要JNDI资源的标准机制,那么你需要游说J2EE专家小组。
结论
只要使用在这篇文章的开头提出的解决方案(但是,为了以防万一,请记住, 理论上可以使用它产生的JNDI相关的问题)。
另一种解决方案
迈克尔·奥西波夫用他建议CloseableResourceListener ,防止Web应用程序取消部署过程中由于左开资源的内存泄漏。 所以,你还可以给它一个尝试。
免责声明
对于更新的别名是灵感来自星球大战电影系列。 所有权利属于其各自所有者。
文章来源: JDBC connection pool runs out of connections when Context reload=“true” is enabled in Tomcat