Spring Boot JPA - Konfigurieren der automatischen Wiederverbindung

106

Ich habe eine nette kleine Spring Boot JPA-Webanwendung. Es wird auf Amazon Beanstalk bereitgestellt und verwendet ein Amazon RDS zum Speichern von Daten. Es wird jedoch nicht so oft verwendet und schlägt daher nach einer Weile mit dieser Art von Ausnahme fehl:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Das letzte vom Server erfolgreich empfangene Paket war vor 79.870.633 Millisekunden.
Das letzte erfolgreich an den Server gesendete Paket war vor 79.870.634 Millisekunden. ist länger als der vom Server konfigurierte Wert von 'wait_timeout'. Sie sollten in Betracht ziehen, die Gültigkeit der Verbindung vor der Verwendung in Ihrer Anwendung abzulaufen und / oder zu testen, die vom Server konfigurierten Werte für Client-Zeitüberschreitungen zu erhöhen oder die Connector / J-Verbindungseigenschaft 'autoReconnect = true' zu verwenden, um dieses Problem zu vermeiden.

Ich bin nicht sicher, wie ich diese Einstellung konfigurieren soll, und kann keine Informationen dazu auf http://spring.io finden (eine sehr gute Seite). Was sind einige Ideen oder Hinweise auf Informationen?

stoffer
quelle
Verwenden Sie diese Option, DataSourceum Ihre Eigenschaften auszudrucken und zu überprüfen. stackoverflow.com/a/36586630/148844 Spring Boot konfiguriert das nicht automatisch, DataSourcewenn Sie welche haben, @Beansdie a definieren DataSource. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/…
Chloe

Antworten:

140

Ich gehe davon aus, dass Boot das DataSourcefür Sie konfiguriert . In diesem Fall und da Sie MySQL verwenden, können Sie Folgendes zu Ihrem application.propertiesbis zu 1.3 hinzufügen

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

Wie djxak im Kommentar erwähnt, 1.4+ definiert spezifische Namensräume für die vier Verbindungen Pools Frühjahr Boot - Träger: tomcat, hikari, dbcp, dbcp2( dbcpals 1.5 veraltet). Sie müssen überprüfen, welchen Verbindungspool Sie verwenden und ob diese Funktion unterstützt wird. Das obige Beispiel war für Tomcat, daher müssten Sie es in 1.4+ wie folgt schreiben:

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

Beachten Sie, dass die Verwendung von autoReconnectwird nicht empfohlen :

Die Verwendung dieser Funktion wird nicht empfohlen, da sie Nebenwirkungen im Zusammenhang mit dem Sitzungsstatus und der Datenkonsistenz hat, wenn Anwendungen SQLExceptions nicht ordnungsgemäß verarbeiten, und nur dann verwendet werden kann, wenn Sie Ihre Anwendung nicht für die Verarbeitung von SQLExceptions konfigurieren können, die sich daraus ergeben tote und veraltete Verbindungen richtig.

Stephane Nicoll
quelle
8
Das liegt daran, dass wir die Art und Weise, wie wir Schlüssel in der Dokumentation schreiben, harmonisiert haben. Früher haben wir immer eine entspannte Bindemittel so beide spring.datasource.testOnBorrowund spring.datasource.test-on-borrowganz gut funktioniert. Weitere Informationen finden Sie in der Dokumentation .
Stephane Nicoll
17
Da dies andere verwirren kann: SELECT 1Garantiert, dass die Verbindung getestet wurde, bevor sie an die Anwendung übergeben wird. Durch die Verwendung testOnBorrow = truewerden die Objekte validiert, bevor sie aus dem Pool ausgeliehen werden. Wenn das Objekt nicht validiert werden kann, wird es aus dem Pool entfernt und versucht, ein anderes auszuleihen. HINWEIS - Damit ein wahrer Wert eine Auswirkung hat, muss der ParameteralidQuery auf eine Zeichenfolge ungleich Null gesetzt werden.
Rick
14
Warnung! Im Frühjahr Boot - 1.4+ dies wurde geändert : Es gibt neue spezifische Namensräume für die vier Verbindungen Pools Federstützen definiert wurde: tomcat, hikari, dbcp, dbcp2. Für den tomcat-jdbcVerbindungspool sollten die Eigenschaften beispielsweise wie folgt lauten: spring.datasource.tomcat.testOnBorrow=trueund spring.datasource.tomcat.validationQuery=SELECT 1.
Ruslan Stelmachenko
1
Wenn ich selbst zwei verschiedene Datenquellen konfiguriere, wie kann ich diese Konfiguration bereitstellen? Muss ich diese Konfiguration sowohl für die Datenquelle wie spring.datasource.mydatasource1.tomcat.testOnBorrow = true spring.datasource.mydatasource1.tomcat.validationQuery = SELECT 1 spring.datasource.mydatasource2.tomcat.testOnBorrow = true spring.datasource bereitstellen. mydatasource2.tomcat.validationQuery = SELECT 1 Oder gibt es noch etwas zu folgen?
Nitish Kumar
2
Warnung! Wenn Sie irgendeine Datasource @Bean in Ihrer Anwendung definieren, dann Frühling - Boot nicht den Pool konfigurieren. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/… If you define your own DataSource bean, auto-configuration will not occur. Ich folgte einer Anleitung für OAuth2 und hatte @Bean(name = "OAuth") public DataSource secondaryDataSource()...und es wurde weder automatisch konfiguriert noch verwendet testOnBorrow.
Chloe
28

Die obigen Vorschläge haben bei mir nicht funktioniert. Was wirklich funktionierte, war die Aufnahme der folgenden Zeilen in die application.properties

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

Die Erklärung finden Sie hier

Soumya
quelle
5
Der von Ihnen hinzugefügte Link lautet: Wenn die Datenbankverbindung länger als 8 Stunden inaktiv ist, wird sie automatisch geschlossen und der obige Fehler tritt auf. Ihre Lösung besteht also darin, die Verbindung nicht für längere Zeit inaktiv zu lassen. Gibt es eine Möglichkeit, nach dem Neustart eine Verbindung zum SQL Server herzustellen?
Akeshwar Jha
9

Die Einstellung spring.datasource.tomcat.testOnBorrow=truein application.properties hat nicht funktioniert.

Die programmgesteuerte Einstellung wie unten funktionierte ohne Probleme.

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);
}
Wer bin ich
quelle
1
Wenn Sie eine benutzerdefinierte Datenquelle deklarieren, liegt dies möglicherweise daran, dass Sie versuchen, die Spring-Standardeinstellung .tomcat zu verwenden. Wenn Sie also eine benutzerdefinierte Datenquellen-Bean erstellen, fügen Sie der DataSource-Bean die @ConfigurationProperties (Präfix = "spring.datasource.tomcat") hinzu, und Sie sollten sie dann in den Anwendungseigenschaften festlegen können. Mein Beispiel .. @Bean (name = "managementDataSource") @ConfigurationProperties (prefix = "management.datasource") public DataSource dataSource () {return DataSourceBuilder.create (). Build (); } Management.datasource.test-on-Borrow = true
Justin
8

Ich bin gerade zu Spring Boot 1.4 gewechselt und habe festgestellt, dass diese Eigenschaften umbenannt wurden:

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
quelle
2
Die Namen sind gleichwertig. Weitere Informationen finden Sie im Abschnitt zur Benennung von Eigenschaften in den Spring Boot-Dokumenten .
Stephen Harrison
@StephenHarrison: Beachten Sie das in 1.4 hinzugefügte Präfix dbcp. *. In diesem Fall gilt die entspannte Bindung nicht.
YM
1
@Pawel: Abhängig davon, welche Pooling-Implementierung in Ihrem Projekt verfügbar ist, handelt es sich möglicherweise nicht um die dbcp. * -Eigenschaften für Sie, siehe Spring Boot mit SQL und den entsprechenden Datenquelleneigenschaften
YM
4

whoamis Antwort ist die richtige. Mit den vorgeschlagenen Eigenschaften konnte ich dies nicht zum Laufen bringen (mit Spring Boot 1.5.3.RELEASE)

Ich füge meine Antwort hinzu, da es sich um eine vollständige Konfigurationsklasse handelt, die möglicherweise jemandem bei der Verwendung von Spring Boot hilft:

@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
quelle
Wissen Sie, warum dieser benutzerdefinierte Code benötigt wird und warum Spring diese Eigenschaften nicht einfach aus der Eigenschaftendatei liest? Ich habe mehrere Datenquelleneigenschaften in meiner Datei und sie liest alle anderen ohne Probleme.
Onkel Long Hair
3

Ich habe ein ähnliches Problem. Spring 4 und Tomcat 8. Ich löse das Problem mit der Spring-Konfiguration

<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>

Ich habe getestet. Es funktioniert gut! Diese beiden Zeilen tun alles, um die Verbindung zur Datenbank wiederherzustellen:

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

Falls jemand eine benutzerdefinierte DataSource verwendet

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

Die Eigenschaften sollten wie folgt aussehen. Beachten Sie die @ConfigurationProperties mit Präfix. Das Präfix steht vor dem eigentlichen Eigenschaftsnamen

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

Eine Referenz für Spring Version 1.4.4.RELEASE

Justin
quelle
2

Wie einige bereits erwähnt haben, verfügt Spring-Boot 1.4+ über spezifische Namespaces für die vier Verbindungspools. Standardmäßig wird Hikaricp in Spring-Boot 2+ verwendet. Sie müssen hier also die SQL angeben. Der Standardwert ist SELECT 1. Folgendes würden Sie beispielsweise für DB2 benötigen: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

Vorsichtsmaßnahme : Wenn Ihr Treiber JDBC4 unterstützt, wird dringend empfohlen, diese Eigenschaft nicht festzulegen. Dies gilt für "Legacy" -Treiber, die die JDBC4 Connection.isValid () - API nicht unterstützen. Dies ist die Abfrage, die ausgeführt wird, kurz bevor Sie eine Verbindung aus dem Pool erhalten, um zu überprüfen, ob die Verbindung zur Datenbank noch besteht. Versuchen Sie erneut, den Pool ohne diese Eigenschaft auszuführen. HikariCP protokolliert einen Fehler, wenn Ihr Treiber nicht JDBC4-kompatibel ist, um Sie darüber zu informieren. Standard: keine

code4kix
quelle
0

Für diejenigen, die dies von YAML aus mit mehreren Datenquellen tun möchten, gibt es einen großartigen Blog-Beitrag dazu: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot -Anwendung/

Grundsätzlich heißt es, dass Sie beide Datenquelleneigenschaften und Datenquellen wie folgt konfigurieren müssen:

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

Vergessen Sie nicht, @Primaryaus anderen Datenquellen zu entfernen .

enesaltinok
quelle