Spring Boot JPA: configuración de la reconexión automática

107

Tengo una pequeña aplicación web Spring Boot JPA. Se implementa en Amazon Beanstalk y utiliza un RDS de Amazon para la persistencia de datos. Sin embargo, no se usa con tanta frecuencia y, por lo tanto, falla después de un tiempo con este tipo de excepción:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: El último paquete recibido correctamente del servidor fue hace 79,870,633 milisegundos.
El último paquete enviado con éxito al servidor fue hace 79,870,634 milisegundos. es más largo que el valor configurado por el servidor de 'wait_timeout'. Debe considerar la caducidad y / o probar la validez de la conexión antes de usarla en su aplicación, aumentar los valores configurados por el servidor para los tiempos de espera del cliente o usar la propiedad de conexión Connector / J 'autoReconnect = true' para evitar este problema.

No estoy seguro de cómo configurar este ajuste y no puedo encontrar información al respecto en http://spring.io (aunque es un sitio muy bueno). ¿Cuáles son algunas ideas o sugerencias de información?

más tieso
fuente
Use esto para imprimir su DataSourcey verificar sus propiedades. stackoverflow.com/a/36586630/148844 Spring Boot no configurará automáticamente el DataSourcesi tiene alguno @Beansque defina un DataSource. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/…
Chloe

Respuestas:

141

Supongo que boot está configurando el DataSourcepara usted. En este caso, y dado que está utilizando MySQL, puede agregar lo siguiente a su application.propertieshasta 1.3

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

Como djxak observó en el comentario, 1.4+ define los espacios de nombres específicos para las cuatro piscinas conexiones soportes de muelle de arranque: tomcat, hikari, dbcp, dbcp2( dbcpestá en desuso como de 1,5). Debe verificar qué grupo de conexiones está utilizando y verificar si esa función es compatible. El ejemplo anterior era para tomcat, por lo que tendría que escribirlo de la siguiente manera en 1.4+:

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

Tenga en cuenta que el uso de autoReconnectestá no recomienda :

No se recomienda el uso de esta función, ya que tiene efectos secundarios relacionados con el estado de la sesión y la coherencia de los datos cuando las aplicaciones no manejan las SQLExceptions correctamente, y solo está diseñada para usarse cuando no puede configurar su aplicación para manejar SQLExceptions resultantes de conexiones muertas y obsoletas correctamente.

Stephane Nicoll
fuente
8
eso es porque hemos armonizado la forma en que escribimos las claves en la documentación. Siempre se utilizó una relajada ligante por lo tanto spring.datasource.testOnBorrowy spring.datasource.test-on-borrowfunciona muy bien. Consulte la documentación para obtener más detalles.
Stephane Nicoll
17
Ya que puede confundir a otros: SELECT 1garantiza que la conexión ha sido probada antes de entregarla a la aplicación. Al usarlos testOnBorrow = true, los objetos se validarán antes de tomarlos prestados del grupo. Si el objeto no se valida, se eliminará del grupo e intentará tomar prestado otro. NOTA - para que un valor verdadero tenga algún efecto, el parámetro validationQuery debe establecerse en una cadena no nula.
Rick
14
¡Advertencia! En la primavera de arranque 1.4+ esto se cambió : no se definió nuevos espacios de nombres específicos para las cuatro conexiones piscinas soportes de muelle: tomcat, hikari, dbcp, dbcp2. Entonces, por ejemplo, para tomcat-jdbcel pool de conexiones, las propiedades deberían ser: spring.datasource.tomcat.testOnBorrow=truey spring.datasource.tomcat.validationQuery=SELECT 1.
Ruslan Stelmachenko
1
Si yo mismo estoy configurando dos fuentes de datos diferentes, ¿cómo proporciono esta configuración? ¿Necesito proporcionar esta configuración tanto para la fuente de datos como spring.datasource.mydatasource1.tomcat.testOnBorrow = true spring.datasource.mydatasource1.tomcat.validationQuery = SELECT 1 spring.datasource.mydatasource2.tomcat.testOnBorrow = true spring.datasource. mydatasource2.tomcat.validationQuery = SELECT 1 ¿O hay algo más a seguir?
Nitish Kumar
2
¡Advertencia! Si define cualquier DataSource @Bean en su aplicación, Spring Boot no configurará el grupo. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/… If you define your own DataSource bean, auto-configuration will not occur. Seguí una guía para OAuth2 @Bean(name = "OAuth") public DataSource secondaryDataSource()...y no se configuró ni se usó automáticamente testOnBorrow.
Chloe
28

Las sugerencias anteriores no funcionaron para mí. Lo que realmente funcionó fue la inclusión de las siguientes líneas en la aplicación.

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

Puedes encontrar la explicación aquí

Soumya
fuente
5
El enlace que ha agregado dice Si la conexión a la base de datos está inactiva durante más de 8 horas, se cierra automáticamente y se producirá el error anterior. Por lo tanto, su solución es no dejar que la conexión permanezca inactiva durante períodos más prolongados. ¿Hay alguna forma de que pueda conectarme al servidor SQL después de que se haya reiniciado?
Akeshwar Jha
9

Ajuste spring.datasource.tomcat.testOnBorrow=true en application.properties no funcionó.

La configuración programática como a continuación funcionó sin ningún problema.

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);
}
quién soy
fuente
1
Si está declarando una fuente de datos personalizada, puede deberse a que está intentando utilizar el .tomcat predeterminado de Spring. Entonces, si crea un bean de origen de datos personalizado, agregue @ConfigurationProperties (prefix = "spring.datasource.tomcat") al bean de origen de datos y luego debería permitirle establecerlos en las propiedades de la aplicación. Mi ejemplo .. @Bean (nombre = "managementDataSource") @ConfigurationProperties (prefix = "management.datasource") public DataSource dataSource () {return DataSourceBuilder.create (). Build (); } management.datasource.test-on -dered = true
Justin
8

Me acabo de mudar a Spring Boot 1.4 y descubrí que estas propiedades cambiaron de nombre:

spring.datasource.dbcp.test-while-idle=true
spring.datasource.dbcp.time-between-eviction-runs-millis=3600000
spring.datasource.dbcp.validation-query=SELECT 1
Jose jurado
fuente
2
Los nombres son equivalentes. Consulte la sección sobre nombres de propiedades en los documentos de Spring Boot .
Stephen Harrison
@StephenHarrison: observe el prefijo dbcp. * Agregado en 1.4, el enlace relajado no se aplica en este caso.
YM
1
@Pawel: dependiendo de qué implementación de agrupación esté disponible en su proyecto, es posible que no sean las propiedades de dbcp. * Para usted, consulte Spring boot con SQL y las propiedades de
YM
4

La respuesta de Whoami es la correcta. Usando las propiedades como se sugirió, no pude hacer que esto funcione (usando Spring Boot 1.5.3.RELEASE)

Estoy agregando mi respuesta ya que es una clase de configuración completa, por lo que podría ayudar a alguien que use 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;
    }
}
naoru
fuente
¿Sabe por qué se necesita este código personalizado y por qué Spring no solo leerá estas propiedades desde el archivo de propiedades? Tengo varias propiedades de origen de datos en mi archivo y lee el resto sin problemas.
Tío Long Hair
3

Tengo un problema similar. Spring 4 y Tomcat 8. Soluciono el problema con la configuración de 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>

He probado. ¡Funciona bien! Esta dos línea hace todo lo posible para volver a conectarse a la base de datos:

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

En caso de que alguien esté usando una fuente de datos personalizada

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

Las propiedades deben tener el siguiente aspecto. Observe las @ConfigurationProperties con prefijo. El prefijo es todo antes del nombre real de la propiedad.

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

Una referencia para Spring Version 1.4.4.

Justin
fuente
2

Como ya señalaron algunas personas, spring-boot 1.4+, tiene espacios de nombres específicos para los cuatro grupos de conexiones. Por defecto, hikaricp se usa en spring-boot 2+. Entonces, tendrá que especificar el SQL aquí. El valor predeterminado es SELECT 1. Esto es lo que necesitaría para DB2, por ejemplo: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

Advertencia : si su controlador es compatible con JDBC4, le recomendamos encarecidamente que no configure esta propiedad. Esto es para controladores "heredados" que no son compatibles con la API JDBC4 Connection.isValid (). Esta es la consulta que se ejecutará justo antes de que se le proporcione una conexión desde el grupo para validar que la conexión a la base de datos aún está activa. Nuevamente, intente ejecutar el grupo sin esta propiedad, HikariCP registrará un error si su controlador no es compatible con JDBC4 para informarle. Por defecto: ninguno

code4kix
fuente
0

Para aquellos que quieran hacerlo desde YAML con múltiples fuentes de datos, hay una excelente publicación de blog al respecto: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot -solicitud/

Básicamente dice que ambos deben configurar las propiedades de la fuente de datos y la fuente de datos de esta manera:

@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();
}

No olvide eliminar @Primaryde otras fuentes de datos.

enesaltinok
fuente