Hibernate 播放框架连接超时问题

Hibernate 播放框架连接超时问题,hibernate,playframework,c3p0,Hibernate,Playframework,C3p0,我有一个play framework Java应用程序(play v1.2.5),它可以正常工作大约一个月,然后产生以下错误: An unexpected error occured caused by exception PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection play.exceptions.UnexpectedException: Unexpecte

我有一个play framework Java应用程序(play v1.2.5),它可以正常工作大约一个月,然后产生以下错误:

An unexpected error occured caused by exception PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection

play.exceptions.UnexpectedException: Unexpected Error
        at play.Invoker$Invocation.onException(Invoker.java:244)
        at play.Invoker$Invocation.run(Invoker.java:286)
        at Invocation.HTTP Request(Play!)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
        at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1389)
        at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1317)
        at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1399)
        at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:63)
        at play.db.jpa.JPAPlugin.startTx(JPAPlugin.java:377)
        at play.db.jpa.JPAPlugin.beforeInvocation(JPAPlugin.java:345)
        at play.plugins.PluginCollection.beforeInvocation(PluginCollection.java:473)
        at play.Invoker$Invocation.before(Invoker.java:217)
        at play.Invoker$Invocation.run(Invoker.java:277)
        ... 1 more
Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
        at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
        at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
        at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
        at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:160)
        at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:81)
        at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1473)
        at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:60)
        ... 6 more
Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
        at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
        at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
        at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:71)
        at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
        ... 11 more
Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@22811ae4 -- timeout at awaitAvailable()
        at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1317)
        at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
        at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
        ... 13 more
如果我重新启动Play,它可以正常工作大约一个月,直到错误再次出现

我的播放设置是:

db.pool.timeout=10000
db.pool.maxSize=500
db.pool.minSize=10
该应用程序连接到本地主机上运行的MySQL数据库。MySQL配置为最多150个连接

MySQL的统计数据包括: mysql>显示类似“%onne%”的状态

+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Aborted_connects         | 546   |
| Connections              | 33197 |
| Max_used_connections     | 127   |
| Ssl_client_connects      | 0     |
| Ssl_connect_renegotiates | 0     |
| Ssl_finished_connects    | 0     |
| Threads_connected        | 11    |
+--------------------------+-------+
从哪里开始调试有什么建议吗

更新: 感谢Steve下面的回答,我发现并修复了一个连接泄漏

我无法通过播放1.2.5使JMX或任何c3p0日志工作。但是…我确实在我的一个控制器中添加了以下方法,允许我按需转储所有必要的c3p0统计数据:

   public static void c3p0() {
        ComboPooledDataSource local = (ComboPooledDataSource) DB.datasource;
        try {
            Logger.info("===============C3P0 STATS================");

            Logger.info("MaxConnectionAge: " + local.getMaxConnectionAge());
            Logger.info("MaxPoolSize: " + local.getMaxPoolSize());
            Logger.info("NumConnectionsAllUsers: " + local.getNumConnectionsAllUsers());
            Logger.info("NumConnectionsDefaultUsers: " + local.getNumConnectionsDefaultUser());

            Logger.info("NumBusyConnectionsAllUsers: " + local.getNumBusyConnectionsAllUsers());
            Logger.info("NumBusyConnectionsDefaultUser: " + local.getNumBusyConnectionsDefaultUser());

            Logger.info("LastCheckinFailureDefaultUser: " + local.getLastCheckinFailureDefaultUser());
            Logger.info("NumFailedCheckinsDefaultUser: " + local.getNumFailedCheckinsDefaultUser());
            Logger.info("NumFailedCheckoutsDefaultUser: " + local.getNumFailedCheckoutsDefaultUser());

            Logger.info("NumIdleConnectionsAllUser: " + local.getNumIdleConnectionsAllUsers());
            Logger.info("NumIdleConnectionsDefaultUser: " + local.getNumIdleConnectionsDefaultUser());

            Logger.info("NumUnclosedOrphanedConnectionsAllUsers: " + local.getNumUnclosedOrphanedConnectionsAllUsers());
            Logger.info("NumUnclosedOrphanedConnectionsDefaultUsers: " + local.getNumUnclosedOrphanedConnectionsDefaultUser());
            Logger.info("===============END STATS================");
            ok();
        } 
        catch (Exception e) {
            error();
        }
    }

play 1.x有一个非常糟糕的地方,那就是它包含以下内容:

这基本上将所有c3p0日志发送到
/dev/null
。所以关于你的问题,你得到的信息比你应该得到的要少

这就是说,这听起来很像一个罕见的连接泄漏。您可以做一件事来验证此集合
db.pool.timeout=0
。然后,应用程序最终应该挂起,而不是抛出您看到的异常。这倒不是更好

另一种方法是定义
c3p0.properties
文件,并将其作为资源放在应用程序的
类路径的顶层。然后,您可以尝试一些播放1不会传递到c3p0的c3p0配置,特别是:

c3p0.unreturnedConnectionTimeout=5
该值应该远低于db.pool.timeout。如果是连接泄漏,这将通过自动清理已检查超过5秒的连接来笨拙地解决问题。通常我强烈建议
c3p0.unreturnedConnectionTimeout
c3p0.debugUnreturnedConnectionStackTraces
配对,这会转储调用getConnection()的代码的堆栈跟踪,然后泄漏它。但是,因为您没有c3p0日志记录,所以这没有什么意义

尽管如此,您所经历的将是一种奇怪的连接泄漏/池耗尽,因为您的池从未达到
maxPoolSize
。不能,因为您的服务器端最大连接数为150

但是,看起来好像你也没有达到这个目标,你最多使用127个连接。如果您有c3p0日志,您可以查看池是否正在尝试在失败之前获取新连接。但你没有。但是,在达到这个极限之前,DBMS的速度可能会急剧下降。如果
Threads\u connected
是您看到这些错误时打开的连接数,很难将其解释为连接泄漏,因为c3p0和DBMS都不应该受到12个打开连接的困扰

同样,c3p0日志将帮助我们非常容易地追踪到这一点:我们可以验证
maxPoolSize
是否是您所认为的,并查看c3p0是否经历了连接获取失败。但我们没有

如果可以连接到JVM以获取JMX数据(例如通过VisualVM),则可以查看一段时间内繁忙连接的数量。如果它一直上升到故障,那就是连接泄漏

如果是连接泄漏,代码中的错误可能会出现在hibernate会话关闭()的地方,但不会出现在finally块中,或者它们在finally块中关闭(),这样就可以跳过finally块中较早发生的异常之前的异常。因此,您可能需要搜索代码库以查找hibernate会话close()发生的位置,并确保会话不可能被创建,并且不会很快关闭(),除了VM退出之外,任何情况下都不会


祝你好运

谢谢你的信息。这非常有帮助。我怀疑某些可能导致连接泄漏的代码。我今晚花了两个小时试图连接JMX(jconsole和VisualVM),但没有成功。我可能只是重构代码,看看它是否有用。所讨论的代码使用无状态会话。确保session.close()似乎很好。但是,有一些语句不显式使用会话,而是使用“Model.find(…)”命令按id从数据库中检索某些特定对象。
c3p0.unreturnedConnectionTimeout=5