Modo corretto per mantenere vivi i collegamenti in pool (o crearli e ottenerne di nuovi) durante l’inattività più lunga per l’app MySQL, Grails 2

Ho un’applicazione per i grails che ha raffiche di alta attività, ma spesso periodi di inattività che possono durare diverse ore fino a notte. Ho notato che i primi utenti al mattino ottengono il seguente tipo di eccezione, e credo che ciò sia dovuto al fatto che le connessioni nel pool stanno diventando obsolete e il database MYSql le chiude.

Ho trovato informazioni in conflitto in Google su se utilizzare la proprietà di connessione Connector / J ‘autoReconnect = true’ è una buona idea (e se il client otterrà comunque un’eccezione anche se la connessione viene ripristinata), o se impostare altre proprietà che periodicamente sfrattano o aggiornano le connessioni inattive, testano i prestiti, ecc. Grails utilizza DBCP sotto. Attualmente dispongo di una semplice configurazione, come di seguito, e sono alla ricerca di una risposta su come meglio garantire che qualsiasi connessione prelevata dal pool dopo un lungo periodo di inattività sia valida e non chiusa.

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

Eccezione

  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) 

Il modo più semplice è configurare il pool di connessioni per specificare la query da eseguire per testare la connessione prima che venga passata all’applicazione:

 validationQuery="select 1 as dbcp_connection_test" testOnBorrow=true 

Questa stessa query di “convalida della connessione” può essere eseguita su altri eventi. Non sono sicuro delle impostazioni predefinite per questi:

 testOnReturn=true testWhileIdle=true 

Esistono anche impostazioni di configurazione che limitano “l’età” delle connessioni inattive nel pool, il che può essere utile se le connessioni inattive vengono chiuse sul server.

 minEvictableIdleTimeMillis timeBetweenEvictionRunsMillis 

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

Non so se sia il modo migliore per gestire la connessione al database, ma ho avuto gli stessi problemi che hai descritto. Ho provato molto e ho finito con il pool di connessioni c3p0 .

Utilizzando c3p0 potresti forzare la tua app ad aggiornare la connessione al database dopo un certo periodo di tempo.

Collocare c3p0.jar nella cartella lib e aggiungere la configurazione a conf/spring/resources.groovy .

Le mie resources.groovy presenta così:

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