38

我有一个 grails 应用程序,它有一系列的高活动,但通常会持续几个小时到一整晚的不活动期。我注意到早上的第一批用户会遇到以下类型的异常,我相信这是由于池中的连接过时并且 MYSql 数据库关闭了它们。

我在谷歌搜索中发现了关于使用 Connector/J 连接属性 'autoReconnect=true' 是否是一个好主意(以及即使连接恢复客户端是否仍会出现异常)或是否设置的冲突信息其他属性会定期驱逐或刷新空闲连接、借用测试等。Grails 在下面使用 DBCP。我目前有一个简单的配置,如下所示,并且正在寻找有关如何最好地确保在长时间不活动期后从池中抓取的任何连接有效且未关闭的答案。

dataSource {
        pooled = true
        dbCreate = "update"
        url = "jdbc:mysql://my.ip.address:3306/databasename"
        driverClassName = "com.mysql.jdbc.Driver"
        dialect = org.hibernate.dialect.MySQL5InnoDBDialect
        username = "****"
        password = "****"
        properties {
          //what should I add here?
          }
    }

例外

    2012-06-20 08:40:55,150 [http-bio-8443-exec-1] ERROR transaction.JDBCTransaction  - JDBC begin failed
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 64,129,968 milliseconds ago.  The last packet sent successfully to the server was 64,129,968 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116)
    at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3851)
    ...... Lots more .......
Caused by: java.sql.SQLException: Already closed.
    at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:114)
4

2 回答 2

37

最简单的方法是配置连接池以指定要运行的查询以在将连接传递给应用程序之前对其进行测试:

validationQuery="select 1 as dbcp_connection_test"
testOnBorrow=true

这个相同的“连接验证”查询可以在其他事件上运行。我不确定这些的默认值:

testOnReturn=true
testWhileIdle=true

还有一些配置设置可以限制池中空闲连接的“年龄”,如果空闲连接在服务器端关闭,这可能很有用。

minEvictableIdleTimeMillis
timeBetweenEvictionRunsMillis

http://commons.apache.org/dbcp/configuration.html

于 2012-06-20T18:50:28.297 回答
9

我不知道这是否是处理数据库连接的最佳方式,但我遇到了与您描述的相同的问题。我尝试了很多,最终得到了c3p0 连接池

使用 c3p0 您可以强制您的应用程序在一定时间后刷新数据库连接。

c3p0.jar放入您的lib文件夹并将您的配置添加到conf/spring/resources.groovy.

我的resources.groovy样子是这样的:

import com.mchange.v2.c3p0.ComboPooledDataSource
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH

beans = {
    /**
    * c3P0 pooled data source that forces renewal of DB connections of certain age
    * to prevent stale/closed DB connections and evicts excess idle connections
    * Still using the JDBC configuration settings from DataSource.groovy
    * to have easy environment specific setup available
    */
    dataSource(ComboPooledDataSource) { bean ->
        bean.destroyMethod = 'close'
        //use grails' datasource configuration for connection user, password, driver and JDBC url
        user = CH.config.dataSource.username
        password = CH.config.dataSource.password
        driverClass = CH.config.dataSource.driverClassName
        jdbcUrl = CH.config.dataSource.url
        //force connections to renew after 4 hours
        maxConnectionAge = 4 * 60 * 60
        //get rid too many of idle connections after 30 minutes
        maxIdleTimeExcessConnections = 30 * 60
    }
 }  
于 2012-06-20T20:44:46.890 回答