web-dev-qa-db-ja.com

MySQL、Grails 2アプリの非アクティブ状態が長い間、プールされた接続を維持する(またはタイムアウトして新しい接続を取得する)正しい方法

私は、高アクティビティの突風を伴うgrailsアプリを持っていますが、その後、数時間から一晩続くことがある非アクティブな期間が多いことがあります。朝の最初のユーザーが次のタイプの例外を受け取ることに気付きました。これは、プール内の接続が古くなり、MYSqlデータベースがそれらを閉じるためであると考えています。

コネクタ/ J接続プロパティ 'autoReconnect = true'を使用するのが良いアイデアであるかどうか(また、接続が復元されてもクライアントが例外を取得するかどうか)、または設定するかどうかについて、Googleで矛盾する情報を見つけましたアイドル接続を定期的に削除または更新する他のプロパティ、借用のテストなど。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)
37
Peter

最も簡単なのは、接続プールを構成して、アプリケーションに渡される前に接続をテストするために実行するクエリを指定することです。

validationQuery="select 1 as dbcp_connection_test"
testOnBorrow=true

この同じ「接続検証」クエリは、他のイベントで実行できます。これらのデフォルトがわからない:

testOnReturn=true
testWhileIdle=true

また、プール内のアイドル接続の「年齢」を制限する構成設定もあります。これは、サーバー側でアイドル接続が閉じられている場合に役立ちます。

minEvictableIdleTimeMillis
timeBetweenEvictionRunsMillis

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

35
spencer7593

データベース接続を処理する最良の方法であるかどうかはわかりませんが、説明したのと同じ問題がありました。私は多くのことを試してみましたが、 c3p0接続プール になりました。

C3p0を使用すると、一定時間後にアプリにデータベース接続を強制的に更新させることができます。

c3p0.jarlibフォルダーに配置し、構成を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
    }
 }  
8
aiolos