MySQL连接超时问题 - 使用Hibernate和ORM在Tomcat上的Grails应用程序

时间:2010-04-29 21:42:38

标签: mysql tomcat grails timeout

我在VPS上的Ubuntu上有一个运行在Tomcat上的小型grails应用程序。我使用MySql作为我的数据存储区,一切正常,除非我离开应用程序超过半天(8小时?)。我做了一些搜索,显然这是mysql.cnf中的默认wait_timeout所以8小时后连接会死,但Tomcat不会知道,当下一个用户试图查看网站时,他们会看到连接失败错误。刷新页面将解决此问题,但我想完全摆脱错误。对于我的MySql版本(5.0.75)我只有my.cnf并且它不包含这样的参数,在任何情况下,更改此参数都无法解决问题。

Blog Post似乎报告了一个类似的错误,但我仍然不完全理解我需要配置什么来解决这个问题,而且我希望有一个比另一个第三方库更简单的解决方案。我正在运行的机器有256MB RAM,我试图将程序/服务的运行数量保持在最低限度。

我可以在Grails / Tomcat / MySql中配置什么来让它消失吗?

提前致谢,

GAV株系

来自我的Catalina.out;

2010-04-29 21:26:25,946 [http-8080-2] ERROR util.JDBCExceptionReporter  - The last packet successfully received from the server was 102,906,722 milliseconds$
2010-04-29 21:26:25,994 [http-8080-2] ERROR errors.GrailsExceptionResolver  - Broken pipe
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
         ...
2010-04-29 21:26:26,016 [http-8080-2] ERROR util.JDBCExceptionReporter  - Already closed.
2010-04-29 21:26:26,016 [http-8080-2] ERROR util.JDBCExceptionReporter  - Already closed.
2010-04-29 21:26:26,017 [http-8080-2] ERROR servlet.GrailsDispatcherServlet  - HandlerInterceptor.afterCompletion threw exception
org.hibernate.exception.GenericJDBCException: Cannot release connection
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.SQLException: Already closed.
        at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:84)
        at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:181)
        ... 1 more

7 个答案:

答案 0 :(得分:18)

参考此article,您的DBCP连接池中存在由操作系统或防火墙静默删除的过时连接。

解决方案是定义验证查询,并在您在应用程序中实际使用它之前对连接进行完整性检查。 在grails中,这实际上是通过修改 grails-app / conf / spring / Resource.groovy 文件并添加以下内容来完成的:

beans = {
  dataSource(BasicDataSource) {
    //run the evictor every 30 minutes and evict any connections older than 30 minutes.
    minEvictableIdleTimeMillis=1800000
    timeBetweenEvictionRunsMillis=1800000
    numTestsPerEvictionRun=3
    //test the connection while its idle, before borrow and return it
    testOnBorrow=true
    testWhileIdle=true
    testOnReturn=true
    validationQuery="SELECT 1"
  }
} 

答案 1 :(得分:5)

在grails 1.3.X中,您可以修改DataSource.groovy文件中的evictor值,以确保在空闲期间使用池化连接。这将确保mysql服务器不会超时连接。

production {
  dataSource {
    pooled = true
    // Other database parameters..
    properties {
       maxActive = 50
       maxIdle = 25
       minIdle = 5
       initialSize = 5
       minEvictableIdleTimeMillis = 1800000
       timeBetweenEvictionRunsMillis = 1800000
       maxWait = 10000
    }
}

验证这种方法的一种快速方法是修改MySQL my.cnf配置文件[mysql]元素并添加一个低值的wait_time参数。

答案 2 :(得分:1)

尝试通过在DataSources.groovy中添加以下内容来增加打开MySQL连接的数量:

dataSource {
     driverClassName = "com.mysql.jdbc.Driver"
     pooled=true
     maxActive=10
     initialSize=5
     // Remaining connection params
}

如果你想要全身心投入,请尝试实现连接池;这是一个useful link

答案 3 :(得分:1)

对于grails 1.3.X,我必须将以下代码添加到Bootstrap.groovy:

  def init = {servletContext ->
  def ctx=servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)

    //implement test on borrow
    def dataSource = ctx.dataSource
    dataSource.targetDataSource.setMinEvictableIdleTimeMillis(1000 * 60 * 30)
    dataSource.targetDataSource.setTimeBetweenEvictionRunsMillis(1000 * 60 * 30)
    dataSource.targetDataSource.setNumTestsPerEvictionRun(3)
    dataSource.targetDataSource.setTestOnBorrow(true)
    dataSource.targetDataSource.setTestWhileIdle(true)
    dataSource.targetDataSource.setTestOnReturn(false)
    dataSource.targetDataSource.setValidationQuery("SELECT 1")

  }

我还必须导入org.codehaus.groovy.grails.commons.ApplicationAttributes

答案 4 :(得分:1)

将这些参数添加到dataSource

        testOnBorrow = true
        testWhileIdle = true
        testOnReturn = true

有关详细信息,请参阅此文章 http://sacharya.com/grails-dbcp-stale-connections/

答案 5 :(得分:0)

grails 2.3.6默认配置开始,已经有防止超时连接的选项

这些是新的默认值。

    properties {
       // See http://grails.org/doc/latest/guide/conf.html#dataSource for documentation
       ....
       minIdle = 5
       maxIdle = 25
       maxWait = 10000
       maxAge = 10 * 60000
       timeBetweenEvictionRunsMillis = 5000
       minEvictableIdleTimeMillis = 60000
       validationQuery = "SELECT 1"
       validationQueryTimeout = 3
       validationInterval = 15000
       testOnBorrow = true
       testWhileIdle = true
       testOnReturn = false
       jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
       defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
    }

答案 6 :(得分:-1)

您的JDBC连接字符串是什么样的?您可以在数据源配置中设置autoReconneect参数,例如

jdbc:mysql://hostname/mydb?autoReconnect=true