Spring Boot JPA: configurazione della riconnessione automatica


107

Ho una piccola applicazione web Spring Boot JPA. Viene distribuito su Amazon Beanstalk e utilizza Amazon RDS per la persistenza dei dati. Tuttavia non viene utilizzato spesso e quindi fallisce dopo un po 'con questo tipo di eccezione:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: L'ultimo pacchetto ricevuto con successo dal server è stato 79.870.633 millisecondi fa.
L'ultimo pacchetto inviato con successo al server è stato 79.870.634 millisecondi fa. è più lungo del valore configurato dal server di "wait_timeout". È necessario considerare la scadenza e / o il test della validità della connessione prima dell'uso nell'applicazione, l'aumento dei valori configurati dal server per i timeout del client o l'utilizzo della proprietà di connessione Connettore / J 'autoReconnect = true' per evitare questo problema.

Non sono sicuro di come configurare questa impostazione e non riesco a trovare informazioni su di essa su http://spring.io (un ottimo sito però). Quali sono alcune idee o suggerimenti alle informazioni?


Usalo per stampare il tuo DataSourcee verificarne le proprietà. stackoverflow.com/a/36586630/148844 Spring Boot non configurerà automaticamente il file DataSourcese ne hai uno @Beansche definisce un file DataSource. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/…
Chloe

Risposte:


141

Presumo che l'avvio stia configurando il file DataSourceper te. In questo caso, e poiché stai usando MySQL, puoi aggiungere quanto segue al tuo application.propertiesfino a 1.3

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

Come djxak notato nel commento, 1.4+ definisce spazi dei nomi specifici per i quattro connessioni piscine supporti Primavera Boot: tomcat, hikari, dbcp, dbcp2( dbcpè deprecato a partire da 1.5). È necessario verificare quale pool di connessioni si sta utilizzando e verificare se tale funzionalità è supportata. L'esempio sopra era per Tomcat, quindi dovresti scriverlo come segue in 1.4+:

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

Si noti che l'uso di autoReconnectè sconsigliato :

L'utilizzo di questa funzione è sconsigliato, perché ha effetti collaterali relativi allo stato della sessione e alla coerenza dei dati quando le applicazioni non gestiscono correttamente SQLExceptions ed è progettato per essere utilizzato solo quando non si è in grado di configurare l'applicazione per gestire SQLExceptions derivanti da connessioni morte e stantie correttamente.


8
questo perché abbiamo armonizzato il modo in cui scriviamo le chiavi nella documentazione. Abbiamo sempre usato un raccoglitore rilassato, quindi entrambi spring.datasource.testOnBorrowe spring.datasource.test-on-borrowfunzioneranno perfettamente. Controlla la documentazione per maggiori dettagli.
Stephane Nicoll

17
Poiché può confondere gli altri: SELECT 1garantisce che la connessione sia stata testata prima di essere passata all'applicazione. Utilizzando testOnBorrow = true, gli oggetti verranno convalidati prima di essere presi in prestito dal pool. Se l'oggetto non riesce a convalidarsi, verrà eliminato dal pool e tenterà di prenderne in prestito un altro. NOTA: affinché un valore true abbia effetto, il parametro validationQuery deve essere impostato su una stringa non nulla.
Rick

14
Avvertimento! Nella primavera del Boot 1.4+ questo è stato cambiato : non è stato definito nuovi spazi dei nomi specifici per i quattro connessioni piscine supporti a molla: tomcat, hikari, dbcp, dbcp2. Quindi, ad esempio, per tomcat-jdbcconnection-pool, le proprietà dovrebbero essere: spring.datasource.tomcat.testOnBorrow=truee spring.datasource.tomcat.validationQuery=SELECT 1.
Ruslan Stelmachenko

1
Se sto configurando personalmente due diverse origini dati, come posso fornire queste configurazioni? Devo fornire questa configurazione sia per l'origine dati come spring.datasource.mydatasource1.tomcat.testOnBorrow = true spring.datasource.mydatasource1.tomcat.validationQuery = SELEZIONA 1 spring.datasource.mydatasource2.tomcat.testOnBorrow = true spring.datasource. mydatasource2.tomcat.validationQuery = SELEZIONA 1 O c'è qualcos'altro da seguire ??
Nitish Kumar

2
Avvertimento! Se definisci un DataSource @Bean nella tua app, Spring Boot non configurerà il pool. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/… If you define your own DataSource bean, auto-configuration will not occur. Ho seguito una guida per OAuth2 e avevo @Bean(name = "OAuth") public DataSource secondaryDataSource()...e non era configurato automaticamente né utilizzato testOnBorrow.
Chloe

28

I suggerimenti di cui sopra non hanno funzionato per me. Ciò che ha funzionato davvero è stata l'inclusione delle seguenti righe in application.properties

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

Puoi trovare la spiegazione qui


5
Il collegamento che hai aggiunto dice Se la connessione al database è inattiva per più di 8 ore, viene automaticamente chiusa e si verificherà l'errore precedente. Quindi, la tua soluzione è non lasciare che la connessione rimanga inattiva per lunghi periodi. C'è un modo per connettermi al server SQL dopo che è stato riavviato?
Akeshwar Jha

9

L'impostazione spring.datasource.tomcat.testOnBorrow=truein application.properties non ha funzionato.

L'impostazione a livello di codice come di seguito ha funzionato senza problemi.

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

1
Se stai dichiarando un'origine dati personalizzata, potrebbe essere perché stai tentando di utilizzare il .tomcat predefinito di primavera. Quindi, se crei un bean Datasource personalizzato, aggiungi @ConfigurationProperties (prefix = "spring.datasource.tomcat") al bean DataSource e dovrebbe permetterti di impostarli nelle proprietà dell'applicazione. Il mio esempio .. @Bean (name = "managementDataSource") @ConfigurationProperties (prefix = "management.datasource") public DataSource dataSource () {return DataSourceBuilder.create (). Build (); } management.datasource.test-on-prestito = true
Justin

8

Sono appena passato a Spring Boot 1.4 e ho scoperto che queste proprietà sono state rinominate:

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

2
I nomi sono equivalenti. Vedere la sezione sulla denominazione delle proprietà nella documentazione di Spring Boot .
Stephen Harrison,

@StephenHarrison: nota il prefisso dbcp. * Aggiunto in 1.4, il binding rilassato non si applica in questo caso.
YM

1
@Pawel: a seconda di quale implementazione del pool è disponibile nel tuo progetto, potrebbe non essere la proprietà dbcp. * Per te, vedi Spring boot con SQL e le corrispondenti proprietà Datasource
YM

4

La risposta di whoami è quella corretta. Utilizzando le proprietà come suggerito non sono riuscito a farlo funzionare (utilizzando Spring Boot 1.5.3.RELEASE)

Sto aggiungendo la mia risposta poiché è una classe di configurazione completa, quindi potrebbe aiutare qualcuno che usa 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;
    }
}

Sai perché è necessario questo codice personalizzato e perché Spring non si limita a leggere queste proprietà dal file delle proprietà? Ho diverse proprietà dell'origine dati nel mio file e le legge tutte le altre senza problemi.
Uncle Long Hair

3

Ho un problema simile. Spring 4 e Tomcat 8. Risolvo il problema con la configurazione 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>

Ho provato Funziona bene! Queste due righe fanno di tutto per riconnettersi al database:

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

3

Nel caso in cui qualcuno utilizzi DataSource personalizzato

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

Le proprietà dovrebbero apparire come le seguenti. Notare @ConfigurationProperties con prefisso. Il prefisso è tutto ciò che precede il nome effettivo della proprietà

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

Un riferimento per la versione Spring 1.4.4.RELEASE


2

Come alcune persone hanno già sottolineato, spring-boot 1.4+, ha spazi dei nomi specifici per i quattro pool di connessioni. Per impostazione predefinita, hikaricp viene utilizzato in spring-boot 2+. Quindi dovrai specificare l'SQL qui. L'impostazione predefinita è SELECT 1. Ecco cosa ti serve per DB2, ad esempio: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

Avvertenza : se il tuo driver supporta JDBC4, consigliamo vivamente di non impostare questa proprietà. Questo è per driver "legacy" che non supportano l'API JDBC4 Connection.isValid (). Questa è la query che verrà eseguita appena prima che ti venga fornita una connessione dal pool per verificare che la connessione al database sia ancora attiva. Di nuovo, prova a eseguire il pool senza questa proprietà, HikariCP registrerà un errore se il tuo driver non è conforme a JDBC4 per farti sapere. Predefinito: nessuno


0

Per coloro che vogliono farlo da YAML con più fonti di dati, c'è un ottimo post sul blog a riguardo: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot -applicazione/

Fondamentalmente dice che entrambi dovete configurare le proprietà dell'origine dati e l'origine dati in questo modo:

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

Non dimenticare di rimuovere @Primaryda altre origini dati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.