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

Geo*_*old 11 java hibernate jpa connection-pooling java-ee

我正在使用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)
Run Code Online (Sandbox Code Playgroud)

我尝试在我的使用中使用以下内容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"/>
Run Code Online (Sandbox Code Playgroud)

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

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

我应该提一下我是如何在我的应用程序中实际使用连接的.我有一个自定义Servlet过滤器拦截所有请求.它创建一个EntityManager,将其存储在ThreadLocal中,并由catch/finally块中的过滤器关闭.我的所有实体获取到的参考EntityManager距离ThreadLocal.

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

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

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

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

在此输入图像描述

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

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

jpk*_*ing 5

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


mat*_*t b 2

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

只是瞎猜,但您是否考虑过autoReconnect=true在 JDBC 驱动程序中设置该属性?或者考虑禁用客户端连接超时的服务器端设置。