Правильный способ сохранить объединенные соединения в живых (или время их выхода и получить свежие) в течение более длительного времени бездействия для MySQL, приложение Grails 2
У меня есть приложение grails, в котором есть потоки высокой активности, но часто это периоды бездействия, которые могут длиться несколько часов до ночи. Я заметил, что первые пользователи получают следующий вид исключения, и я считаю, что это связано с тем, что соединения в пуле становятся устаревшими, а база данных MYSql закрывает их.
Я нашел противоречивую информацию в Googling о том, является ли использование свойства Connector/J connection '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)
Ответы
Ответ 1
Проще всего настроить пул соединений, чтобы указать запрос, который должен быть запущен, чтобы протестировать соединение до его передачи в приложение:
validationQuery="select 1 as dbcp_connection_test"
testOnBorrow=true
Этот же запрос проверки соединения может быть запущен на других событиях. Я не уверен в значениях по умолчанию для них:
testOnReturn=true
testWhileIdle=true
Существуют также настройки конфигурации, которые ограничивают "возраст" незанятых соединений в пуле, что может быть полезно, если соединения на холостом ходу закрываются на сервере.
minEvictableIdleTimeMillis
timeBetweenEvictionRunsMillis
http://commons.apache.org/dbcp/configuration.html
Ответ 2
Я не знаю, является ли это наилучшим способом обработки подключения к базе данных, но у меня были те же проблемы, что и вы. Я много пробовал и закончил с 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
}
}