web-dev-qa-db-fra.com

Façon correcte de maintenir en vie les connexions regroupées (ou de les expirer et d'en obtenir de nouvelles) pendant une inactivité plus longue pour MySQL, l'application Grails 2

J'ai une application Grails qui a des rafales d'activité élevée, mais souvent des périodes d'inactivité qui peuvent durer plusieurs heures ou toute la nuit. Je remarque que les premiers utilisateurs du matin obtiennent le type d'exception suivant, et je pense que cela est dû aux connexions dans le pool qui deviennent obsolètes et à la fermeture de la base de données MYSql.

J'ai trouvé des informations contradictoires dans Google pour savoir si l'utilisation de la propriété de connexion Connecteur/J 'autoReconnect = true' est une bonne idée (et si le client recevra toujours une exception même si la connexion est ensuite rétablie), ou s'il faut définir d'autres propriétés qui vont périodiquement expulser ou rafraîchir les connexions inactives, les tester lors de l'emprunt, etc. Grails utilise DBCP en dessous. J'ai actuellement une configuration simple comme ci-dessous, et je cherche une réponse sur la meilleure façon de garantir que toute connexion récupérée hors du pool après une longue période d'inactivité est valide et non fermée.

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?
          }
    }

Exception

    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

Le plus simple consiste à configurer le pool de connexions pour spécifier la requête à exécuter pour tester la connexion avant de la transmettre à l'application:

validationQuery="select 1 as dbcp_connection_test"
testOnBorrow=true

Cette même requête "validation de connexion" peut être exécutée sur d'autres événements. Je ne suis pas sûr des valeurs par défaut pour celles-ci:

testOnReturn=true
testWhileIdle=true

Il existe également des paramètres de configuration qui limitent l '"âge" des connexions inactives dans le pool, ce qui peut être utile si les connexions inactives sont fermées du côté serveur.

minEvictableIdleTimeMillis
timeBetweenEvictionRunsMillis

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

35
spencer7593

Je ne sais pas si c'est la meilleure façon de gérer la connexion à la base de données, mais j'ai eu les mêmes problèmes que vous avez décrits. J'ai beaucoup essayé et je me suis retrouvé avec le pool de connexions c3p .

En utilisant c3p0, vous pouvez forcer votre application à actualiser la connexion à la base de données après un certain temps.

Placer le c3p0.jar dans votre dossier lib et ajoutez votre configuration à conf/spring/resources.groovy.

Ma resources.groovy ressemble à ça:

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