Spring Boot JPA - настройка автоматического переподключения

У меня есть симпатичное маленькое веб-приложение Spring Boot JPA. Он развернут в Amazon Beanstalk и использует Amazon RDS для сохранения данных. Однако он не используется так часто, и поэтому через некоторое время терпит неудачу с таким исключением:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Последний пакет, успешно полученный от сервера, был 79 870 633 миллисекунд назад.
Последний пакет, успешно отправленный на сервер, был 79 870 634 миллисекунд назад. больше, чем сконфигурированное сервером значение wait_timeout. Чтобы избежать этой проблемы, следует рассмотреть возможность истечения срока действия и / или проверки допустимости соединения перед использованием в приложении, увеличения значений, настроенных сервером для тайм-аутов клиента, или использования свойства соединения Connector/J "autoReconnect=true".

Я не уверен, как настроить этот параметр и не могу найти информацию о нем на http://spring.io/ (хотя очень хороший сайт). Каковы некоторые идеи или указатели на информацию?

7 ответов

Решение

Я предполагаю, что загрузка настраивает DataSource для тебя. В этом случае, так как вы используете MySQL, вы можете добавить следующее к вашему application.properties до 1,3

spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1

Как отмечено в комментарии djxak, 1.4+ определяет конкретные пространства имен для четырех пулов соединений, которые поддерживает Spring Boot: tomcat, hikari, dbcp, dbcp2 (dbcp устарело с 1.5). Вам необходимо проверить, какой пул соединений вы используете, и проверить, поддерживается ли эта функция. Приведенный выше пример был для tomcat, поэтому вы должны написать его в 1.4+ следующим образом:

spring.datasource.tomcat.testOnBorrow=true 
spring.datasource.tomcat.validationQuery=SELECT 1

Обратите внимание, что использование autoReconnect не рекомендуется:

Использование этой функции не рекомендуется, поскольку она имеет побочные эффекты, связанные с состоянием сеанса и согласованностью данных, когда приложения не обрабатывают SQLExceptions должным образом, и предназначена только для случаев, когда вы не можете настроить приложение для обработки SQLExceception, возникающих в результате мертвые и несвежие соединения правильно.

Вышеуказанные предложения не работают для меня. Что действительно сработало, так это включение следующих строк в application.properties

spring.datasource.testWhileIdle = true
spring.datasource.timeBetweenEvictionRunsMillis = 3600000
spring.datasource.validationQuery = SELECT 1

Вы можете найти объяснение здесь

Настройка spring.datasource.tomcat.testOnBorrow=true в приложении. свойства не работают.

Программная настройка, как показано ниже, работала без проблем.

import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;    

@Bean
public DataSource dataSource() {
    PoolProperties poolProperties = new PoolProperties();
    poolProperties.setUrl(this.properties.getDatabase().getUrl());         
    poolProperties.setUsername(this.properties.getDatabase().getUsername());            
    poolProperties.setPassword(this.properties.getDatabase().getPassword());

    //here it is
    poolProperties.setTestOnBorrow(true);
    poolProperties.setValidationQuery("SELECT 1");

    return new DataSource(poolProperties);
}

Я только что перешел на Spring Boot 1.4 и обнаружил, что эти свойства были переименованы:

spring.datasource.dbcp.test-while-idle=true
spring.datasource.dbcp.time-between-eviction-runs-millis=3600000
spring.datasource.dbcp.validation-query=SELECT 1

Ответ Whoami является правильным. Используя предложенные свойства, я не смог заставить это работать (с помощью Spring Boot 1.5.3.RELEASE)

Я добавляю свой ответ, так как это полный класс конфигурации, поэтому он может помочь кому-то, использующему Spring Boot:

@Configuration
@Log4j
public class SwatDataBaseConfig {

    @Value("${swat.decrypt.location}")
    private String fileLocation;

    @Value("${swat.datasource.url}")
    private String dbURL;

    @Value("${swat.datasource.driver-class-name}")
    private String driverName;

    @Value("${swat.datasource.username}")
    private String userName;

    @Value("${swat.datasource.password}")
    private String hashedPassword;

    @Bean
    public DataSource primaryDataSource() {
        PoolProperties poolProperties = new PoolProperties();
        poolProperties.setUrl(dbURL);
        poolProperties.setUsername(userName);
        poolProperties.setPassword(password);
        poolProperties.setDriverClassName(driverName);
        poolProperties.setTestOnBorrow(true);
        poolProperties.setValidationQuery("SELECT 1");
        poolProperties.setValidationInterval(0);
        DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
        return ds;
    }
}

У меня похожая проблема. Spring 4 и Tomcat 8. Я решаю проблему с конфигурацией Spring

<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
    <property name="initialSize" value="10" />
    <property name="maxActive" value="25" />
    <property name="maxIdle" value="20" />
    <property name="minIdle" value="10" />
     ...
    <property name="testOnBorrow" value="true" />
    <property name="validationQuery" value="SELECT 1" />
 </bean>

Я проверил. Это работает хорошо! Эти две строки делают все для того, чтобы переподключиться к базе данных:

<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="SELECT 1" />

В случае, если кто-то использует пользовательский источник данных

@Bean(name = "managementDataSource")
@ConfigurationProperties(prefix = "management.datasource")
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}

Свойства должны выглядеть следующим образом. Обратите внимание на @ConfigurationProperties с префиксом. Префикс - это все перед фактическим именем свойства

management.datasource.test-on-borrow=true
management.datasource.validation-query=SELECT 1

Ссылка на версию Spring 1.4.4.RELEASE

Как уже отмечали некоторые пользователи, у Spring-boot 1.4+ есть определенные пространства имен для четырех пулов соединений. По умолчанию hikaricp используется в spring-boot 2+. Так что вам придется указать здесь SQL. По умолчанию SELECT 1, Вот что вам нужно для DB2, например: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

Предупреждение: если ваш драйвер поддерживает JDBC4, мы настоятельно рекомендуем не устанавливать это свойство. Это для устаревших драйверов, которые не поддерживают API JDBC4 Connection.isValid(). Это запрос, который будет выполнен непосредственно перед тем, как вам будет дано соединение из пула, чтобы проверить, что соединение с базой данных еще живо. Снова, попробуйте запустить пул без этого свойства, HikariCP будет регистрировать ошибку, если ваш драйвер не совместим с JDBC4, чтобы сообщить вам. По умолчанию: нет

Для тех, кто хочет сделать это из YAML с несколькими источниками данных, есть отличное сообщение в блоге об этом: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot-application/

В основном это говорит о том, что вам обоим нужно настроить свойства источника данных и источник данных следующим образом:

@Bean
@Primary
@ConfigurationProperties("app.datasource.member")
public DataSourceProperties memberDataSourceProperties() {
    return new DataSourceProperties();
}

@Bean
@Primary
@ConfigurationProperties("app.datasource.member.hikari")
public DataSource memberDataSource() {
    return memberDataSourceProperties().initializeDataSourceBuilder()
            .type(HikariDataSource.class).build();
}

Не забудьте удалить @Primary из других источников данных.

Другие вопросы по тегам