Guice JPA - “此连接已关闭。”错误

时间:2012-10-16 13:08:23

标签: jpa guice guice-persist

数据库丢弃空闲连接或数据库关闭并备份后我在webapp中收到以下错误:

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包含好的和坏的连接的混合,并且问题似乎随着时间的推移清除,但我让服务器运行> 12h并且仍然有错误的连接返回。 重启后,evertything工作正常(一段时间)。

我已经对问题进行了一些调试,看起来池正在返回错误的连接,例如如果我在DB上杀死所有连接后,我得到:

SQL Error: 0, SQLState: 57P01

然后是通常的东西 - 从池中返回被杀死的连接。 问题是:它是一个应用程序问题吗?

我尝试通过JMX清除池,但这似乎没有任何影响。 另一个奇怪的事情是,即使app显然没有做任何事情(通过线程转储检查),JMX bean显示7个活动连接和0个空闲连接。当我执行需要DB访问的请求时,我立即得到响应(假设没有可用的空闲连接),但JMX在此之后显示7个活动连接和0个空闲连接。

PS。也许我错过了一些明显的东西,这是我的连接管理问题?我正在使用通过persistence.xml配置的JPA EntityManager,所以也许我做错了,连接在使用后没有正确关闭(返回)?

3 个答案:

答案 0 :(得分:5)

一个惊人的镜头:代码here建议,validationInterval也会检查testOnBorrow

由于您将此值从30秒默认值设置为5分钟,这意味着在DB断开连接后的5分钟内,您仍然可以获得该陈旧连接。如果你的数据库超时不到5分钟......运气不好。

为了测试这个理论,你可以将validationInterval设置为荒谬的低值。

如果这有帮助(阅读:我们找到了正确的旋钮),您应该将其设置为至少比数据库超时更短的时间。因此,当DB决定删除空闲连接时,较低的validationInterval将确保在下一次借用之前检查连接。由于数据库服务器重启(即没有超时)而导致的封闭连接不受此解决方案的影响,但至少恢复到理智状态的时间也会降低。

注意:我刚刚向Google询问了代码。我不知道这是实际代码还是古代代码。

答案 1 :(得分:5)

实际上,当我怀疑应用程序错误时,我是对的。

Issue 730: Automatically started UnitOfWork is never ended

中很好地描述了这一切
  

使用JpaPersistService时,如果您尝试访问   在一个活跃的UnitOfWork之外的EntityManager,Guice会   自动为您启动一个。但是,因为Guice没有(和   不知道何时结束这个UnitOfWork,它永远不会。

     

结果?违规线程将使用相同的EntityManager   在整个应用程序的生命周期。这是一个糟糕的状态   应用程序运行,我们不可避免地耗尽可用   一段时间后内存崩溃。

     

这里真正的杀手是,当你做出来时,它并不是很明显   这个错误。唯一真正的提示就是你得到了   不同线程之间数据库中的数据不一致(由于   EMs第一级缓存)或应用程序内存消耗   不断发展。   在我的情况下,池中的活动连接让我怀疑它,然后,当我打开详细日志记录时,我注意到应用程序根本没有从池中借用连接,而是重新使用已经由未公开的EntityManager。

实际上,报告的这个问题有一些重复:http://code.google.com/p/google-guice/issues/list?can=1&q=UnitOfWork

答案 2 :(得分:0)

如果您修改了META-INF/context.xml以包含validationQuery,则Tomcat可能会在conf/engine/host/webapp.xml下缓存旧定义。关闭Tomcat,删除该文件,然后重新启动Tomcat。在Tomcat关闭时删除work目录也没什么坏处。