帮助我避免与JPA,Hibernate和MySQL的连接超时

我正在使用JPA(Hibernate作为提供者),Glassfish和MySQL。 一切都在开发中很好用,但是当我将应用程序部署到测试服务器并让它在一夜之间运行(大部分空闲)时,我通常会在早上受到欢迎:

[#|2011-03-09T15:06:00.229+0000|INFO|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=23;_ThreadName=Thread-1;|ERROR [htt\ p-thread-pool-8080-(1)] (JDBCTransaction.java:91) - JDBC begin failed com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 41,936,868 milliseconds ago. The last packet \ sent successfully to the server was 41,936,868 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expirin\ g and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connec\ tion property 'autoReconnect=true' to avoid this problem. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:532) at com.mysql.jdbc.Util.handleNewInstance(Util.java:409) at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1118) at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3321) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1940) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2562) at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:4956) at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:87) at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1473) at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:60) 

我尝试在persistence.xml使用以下内容,但它没有帮助:

       

这就是C3p0配置; 完全有可能我错过了实际告诉hibernate的部分“嘿,使用c3p0”。

我即将尝试在错误消息中找到正确的建议:将autoReconnect=true添加到我的JDBC URL中,但这真的开始感觉像此时的货物开发。 对于解决这个问题的正确方法,我将不胜感激。 它很难调试,因为测试周期实际上是“一夜之间运行,看看早上会发生什么”。

我应该提一下我在我的应用程序中实际使用连接的方式。 我有一个自定义Servletfilter拦截所有请求。 它创建一个EntityManager,将其存储在ThreadLocal中,并由catch / finally块中的filter关闭。 我的所有实体都从ThreadLocal获取对EntityManager的引用。

我的filter完全有可能出错,但由于它似乎只是在闲置期后发生,我怀疑还有其他错误。 当我有机会喘口气时,我打算搬到Seam / Weld,但是现在我依靠这个filter。

编辑:这是TL; DR解决方案:

  • 如果可以,请使用容器的连接池(谢谢,@ partenon)
  • 确保您的连接池使用连接validation (谢谢,@matt b)

就我而言,我必须在Resources / JDBC / Connection Pools,Advanced选项卡下进入Glassfish控制台,然后启用连接validation:

在此处输入图像描述

这确实是至关重要的一步。 你也可能想要将Validate At Most Once设置为合理的,比如说100秒。 如果您使用的是C3P0或类似产品,请确保配置idle_test_periodpreferredTestQuery

无论您最终做什么,测试您的更改以确定它们是否具有所需效果非常重要。 为了在MySQL中更快地发生超时,你可以通过编辑my.cnf暂时将wait_timeout设置为30秒的低点。 这是调试此问题的巨大帮助,因为它允许我在几秒钟而不是几小时内测试更改。

您应该考虑在应用程序中使用之前到期和/或测试连接有效性,增加服务器配置的客户端超时值,或使用Connector / J连接属性“autoReconnect = true”来避免此问题。

只是在黑暗中拍摄,但您是否看过在JDBC驱动程序中设置autoReconnect=true属性? 或者考虑禁用服务器端设置以进行客户端连接超时。

我认为真正的问题是:为什么使用外部连接池机制而不是使用Glassfish自己的池? 您的应用服务器更适合为您的应用提供此类服务。 “外部”连接池机制更适合独立应用程序,而不适用于容器内应用程序。

我认为根据C3P0文档,设置连接测试周期的属性是idle_test_period ,而不是idleTestPeriod 。 所以你应该使用:

  

代替。

我遇到了同样的问题,需要时间来找出解决方案。

我使用Hibernate 4.0.1和mysql 5.1(没有spring框架),我正面临着这个问题。 首先确保您正确配置了c3p0jar,这是必不可少的。

我在hibernate.cfg.xml中使用了这些属性

 true org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider 5 20 50 SELECT 1; true 10 5 200 40 

但它没有用’因为C3p0仍然采用默认属性而不是我在hibernate.cfg.xml中设置的属性,你可以在日志中检查它。 所以,我在许多网站上搜索了正确的解决方案,最后我想出了这个。 删除cfg.xml中的C3p0属性并在根路径中创建c3p0-config.xml(以及cfg.xml)并按如下方式设置属性。

   con_test 40 10 10 20 5 50 SELECT 1; 5 200 30   

但是如果你运行,ORM采用jdbc连接但不采用C3p0连接池,因为我们应该在hibernate.cfg.xml中添加这些属性

 true org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider 

现在一切正常(至少它对我来说很好)并且问题解决了。

检查以下内容以获取参考。

http://www.mchange.com/projects/c3p0/index.html#configuring_connection_testing

https://community.jboss.org/wiki/HowToConfigureTheC3P0ConnectionPool

我希望这能解决你的问题。