帮助我避免与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_period
和preferredTestQuery
。
无论您最终做什么,测试您的更改以确定它们是否具有所需效果非常重要。 为了在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
我希望这能解决你的问题。