Подтвердить что ты не робот

Правильный способ сохранить объединенные соединения в живых (или время их выхода и получить свежие) в течение более длительного времени бездействия для 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)
4b9b3361

Ответ 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
    }
 }