我正在使用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
中使用以下内容,但它没有帮助:
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.idleTestPeriod" value="30"/>
<property name="hibernate.c3p0.timeout" value="0"/>
<property name="hibernate.c3p0.max_statements" value="0"/>
这就是C3p0配置;完全有可能我错过了实际告诉hibernate的部分“嘿,使用c3p0”。
我即将尝试在错误消息中找到正确的建议:将autoReconnect=true
添加到我的JDBC URL中,但此时真的开始感觉像是货物开发。对于解决这个问题的正确方法,我将不胜感激。它很难调试,因为测试周期实际上是“一夜之间运行,看看早上会发生什么”。
我应该提一下我在应用程序中实际使用连接的方式。我有一个自定义Servlet Filter来拦截所有请求。它创建一个EntityManager,将其存储在ThreadLocal中,并由catch / finally块中的过滤器关闭。我的所有实体都会从EntityManager
获取对ThreadLocal
的引用。
我的过滤器完全有可能出错,但由于它似乎只是在闲置期后发生,我怀疑还有其他错误。当我有机会喘口气时,我打算搬到Seam / Weld,但现在我依靠这个过滤器。
编辑:这是TL; DR解决方案:
就我而言,我必须在Resources / JDBC / Connection Pools,Advanced选项卡下进入Glassfish控制台,然后启用连接验证:
这是至关重要的一步。你也可能想把Validate At Most Once
设置为合理的,比如说100秒。如果您使用的是C3P0或类似产品,请务必配置idle_test_period
和preferredTestQuery
。
无论您最终做什么,重要的是测试您的更改,看看它们是否具有所需的效果。为了在MySQL中更快地发生超时,您可以通过编辑wait_timeout
暂时将my.cnf
设置为低至30秒。这对于调试此问题是一个巨大的帮助,因为它允许我在几秒钟而不是几小时内测试更改。
答案 0 :(得分:5)
我认为真正的问题是:为什么使用外部连接池机制而不是使用Glassfish自己的池?您的应用服务器更适合为您的应用提供此类服务。 “外部”连接池机制更适合独立应用程序,而不适用于容器内应用程序。
答案 1 :(得分:2)
在应用程序中使用之前,应考虑使用和/或测试连接有效性,增加服务器配置的客户端超时值,或使用Connector / J连接属性“autoReconnect = true”来避免此问题。
只是在黑暗中拍摄,但您是否看过在JDBC驱动程序中设置autoReconnect=true
属性?或者考虑禁用客户端连接超时的服务器端设置。
答案 2 :(得分:2)
根据C3P0文档here,我认为设置连接测试时间的属性为idle_test_period
,而不是idleTestPeriod
。所以你应该使用:
<property name="hibernate.c3p0.idle_test_period" value="30"/>
代替。
答案 3 :(得分:1)
我遇到了同样的问题,需要时间来找出解决方案。
我使用Hibernate 4.0.1和mysql 5.1(没有spring框架),我遇到了这个问题。首先确保你正确配置了c3p0罐子,这是必不可少的。
我在hibernate.cfg.xml中使用了这些属性
<property name="hibernate.c3p0.validate">true</property>
<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1;</property>
<property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
<property name="hibernate.c3p0.idle_test_period">10</property>
<property name="hibernate.c3p0.acquireRetryAttempts">5</property>
<property name="hibernate.c3p0.acquireRetryDelay">200</property>
<property name="hibernate.c3p0.timeout">40</property>
但它没有用'因为C3p0仍然采用默认属性而不是我在hibernate.cfg.xml中设置的属性,你可以在日志中检查它。所以,我在许多网站上搜索了正确的解决方案,最后我想出了这个。删除cfg.xml中的C3p0属性并在根路径中创建c3p0-config.xml(以及cfg.xml)并按如下方式设置属性。
<c3p0-config>
<default-config>
<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">40</property>
<property name="idleConnectionTestPeriod">10</property>
<property name="initialPoolSize">10</property>
<property name="maxPoolSize">20</property>
<property name="minPoolSize">5</property>
<property name="maxStatements">50</property>
<property name="preferredTestQuery">SELECT 1;</property>
<property name="acquireRetryAttempts">5</property>
<property name="acquireRetryDelay">200</property>
<property name="maxIdleTime">30</property>
</default-config>
</c3p0-config>
但是如果你运行,ORM接受jdbc连接但不接受C3p0连接池,因为我们应该在hibernate.cfg.xml中添加这些属性
<property name="hibernate.c3p0.validate">true</property>
<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
现在一切正常(至少它对我来说很好)并且问题已经解决了。
检查以下内容以供参考。
http://www.mchange.com/projects/c3p0/index.html#configuring_connection_testing
https://community.jboss.org/wiki/HowToConfigureTheC3P0ConnectionPool
我希望这能解决你的问题。