2012-06-20 3 views
33

Ho un'app di Grails che ha raffiche di attività elevata, ma spesso periodi di inattività che possono durare diverse ore per tutta la notte. Ho notato che i primi utenti del mattino ottenere il seguente tipo di eccezione, e credo che questo sia dovuto alle connessioni nel pool di database che vanno stantio e mysql chiuderli.Modo corretto per mantenere vivi i collegamenti in pool (o crearli e recuperarli) durante l'inattività più lunga per MySQL, app Grails 2

Ho trovato informazioni in conflitto su Google 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), oppure se impostare altre proprietà che periodicamente sgomberare o rinfrescare connessioni inattive, test prestito, ecc Grails utilizza DBCP sotto. Al momento ho una semplice configurazione, come di seguito, e sono alla ricerca di una risposta su come garantire meglio che qualsiasi connessione afferrato fuori dalla piscina, dopo un lungo periodo di inattività è valido e non chiuso.

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) 

risposta

29

Il metodo più semplice è quello di configurare il pool di connessione per specificare la query per essere eseguito per verificare la connessione prima che sia passato all'applicazione:

validationQuery="select 1 as dbcp_connection_test" 
testOnBorrow=true 

Questo la stessa query di "convalida della connessione" può essere eseguita su altri eventi. Non sono sicuro dei valori di default per questi:

testOnReturn=true 
testWhileIdle=true 

Ci sono anche le impostazioni di configurazione che limitano "l'età" delle connessioni inattive in piscina, che può essere utile se le connessioni inattive vengono chiuse alla fine del server .

minEvictableIdleTimeMillis 
timeBetweenEvictionRunsMillis 

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

+0

Grazie per il link, riesce a sbagliare anche quella pagina andando direttamente alle javadoc. Implementerò una combinazione di quelli e vedremo come funziona. – Peter

+0

Purtroppo, DBCP non ha ancora una configurazione per limitare l'età della connessione, o il numero di volte che una connessione viene utilizzato, prima di essere sfrattato dalla piscina. (Altre implementazioni dei pool di connessione.) – spencer7593

+0

sebbene, spencer7593, che non dovrebbe importare se le connessioni vengono utilizzate, o sfrattate/aggiornate quando vanno male dall'inattività, penso, in quanto non avrà alcun impatto sull'utente. – Peter

7

Non so se è il modo migliore per gestire la connessione al database, ma ho avuto gli stessi problemi, come si desribed. Ho provato un sacco e si è conclusa con l'c3p0 connection pool.

Utilizzando c3p0 si potrebbe forzare la vostra applicazione per aggiornare la connessione al database dopo un certo tempo.

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

mio resources.groovy assomiglia a questo:

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

+1 Alcune implementazioni del pool di connessioni offrono funzionalità più robuste di DBCP. Le versioni più recenti di DBCP supportano lo sfratto quando è trascorso il "tempo massimo di inattività", ma a DBCP mancano ancora altre opzioni di configurazione, come l'età massima e il numero massimo di utilizzi. – spencer7593

+1

Ho trovato che C3PO funziona molto bene quando si verificano problemi di timeout della connessione su stack Grails. –