在数据库丢弃空闲连接或数据库关闭并备份后,我在我的the应用程序中收到以下错误:
javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException: could not inspect JDBC autocommit mode
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1365)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1293)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:265)
... 60 more
Caused by: org.hibernate.exception.JDBCConnectionException: could not inspect JDBC autocommit mode
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:131)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.isAutoCommit(LogicalConnectionImpl.java:395)
at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.afterNonTransactionalQuery(TransactionCoordinatorImpl.java:195)
at org.hibernate.internal.SessionImpl.afterOperation(SessionImpl.java:565)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1220)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)
... 70 more
Caused by: org.postgresql.util.PSQLException: This connection has been closed.
at org.postgresql.jdbc2.AbstractJdbc2Connection.checkClosed(AbstractJdbc2Connection.java:712)
at org.postgresql.jdbc2.AbstractJdbc2Connection.getAutoCommit(AbstractJdbc2Connection.java:678)
at sun.reflect.GeneratedMethodAccessor138.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:63)
at $Proxy66.getAutoCommit(Unknown Source)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.isAutoCommit(LogicalConnectionImpl.java:392)
当这段代码开始时,我得到一个
SQL Error: 0, SQLState: 08006 - An I/O error occured while sending to the backend.
但在那之后,它只是:
SQL Error: 0, SQLState: 08003 - This connection has been closed.
问题是:我已经设置了testOnBorrow,所以我希望只得到开放的连接。
如果这有帮助的话: ususaly池包含好的和坏的连接,随着时间的推移,问题似乎会消失,但我让服务器运行了超过12小时,仍然有坏连接返回。重新启动后,(在一段时间内)一切正常。
我已经对这个问题进行了更多的调试,似乎池返回了错误的连接,例如,如果我在DB上杀死了所有连接,我会得到:
SQL Error: 0, SQLState: 57P01
然后是常见的东西--被杀死的连接从池中返回。问题是:这是一个应用程序问题吗?
我尝试通过JMX清除池,但似乎没有任何效果。另一件奇怪的事情是,即使应用程序显然没有做任何事情(通过线程转储检查),JMX bean仍然显示7个活动连接和0个空闲连接。当我执行一个需要DB访问的请求时,我立即得到一个响应(说明没有可用的空闲连接),但是JMX显示了7个活动连接和0个空闲连接。
PS。也许我遗漏了一些明显的东西,这是我的连接管理问题?我使用的是通过persistence.xml配置的JPA EntityManager,所以可能我做错了什么,使用后连接没有正确关闭(返回)?
发布于 2012-10-26 12:41:37
实际上,当我怀疑是应用程序错误时,我是对的。
所有这些都在Issue 730: Automatically started UnitOfWork is never ended中进行了很好的描述
在使用JpaPersistService时,如果您尝试在active UnitOfWork之外访问EntityManager,Guice将自动为您启动一个。但是,由于Guice不知道(也不能)何时结束此UnitOfWork,因此它从不知道。
结果呢?在应用程序的整个生命周期中,违规线程将使用相同的EntityManager。对于运行应用程序来说,这是一种糟糕的状态,我们的应用程序不可避免地会在一段时间后耗尽可用内存并崩溃。
这里真正的杀手是,当你犯了这个错误时,它一点都不明显。唯一真正的提示是,您在不同的线程之间从数据库中获得了不一致的数据(由于EM一级缓存),或者应用程序的内存消耗持续增长。在我的例子中,是池中的活动连接让我怀疑它,然后,当我打开详细的日志记录时,我注意到应用程序根本没有从池中借用连接,而是重用了已由未关闭的EntityManager持有的连接。
实际上,这个问题有相当多的副本报道:http://code.google.com/p/google-guice/issues/list?can=1&q=UnitOfWork
发布于 2012-10-16 20:10:29
一个离奇的想法:here建议的代码也检查validationInterval
中是否有testOnBorrow
。
由于您将此值从30秒的默认值设置为5分钟,这意味着在DB断开连接后的5分钟内,您仍然可以获得那个陈旧的连接。如果您的数据库超时小于5分钟...真不走运。
为了测试这个理论,您可以将validationInterval
设置为一个可笑的低值。
如果这有帮助(阅读:我们找到了正确的旋钮),您应该至少将其设置为比DB超时更短的时间。因此,当DB决定丢弃空闲连接时,较低的validationInterval
将确保在下一次借用之前检查该连接。由于数据库服务器重新启动(即没有超时)而关闭的连接不会受到此解决方案的影响,但至少恢复到正常状态的时间也会更短。
注意:我刚刚向谷歌要了代码。我不知道这是真正的代码还是古老的代码。
发布于 2012-10-16 14:30:57
如果您已经修改了META-INF/context.xml
以包含validationQuery
,那么Tomcat很可能会在conf/engine/host/webapp.xml
下缓存旧的定义。关闭Tomcat,删除该文件,然后重新启动Tomcat。在Tomcat关闭的时候删除work
目录也没什么坏处。
https://stackoverflow.com/questions/12915427
复制