Spring Boot JPA - định cấu hình tự động kết nối lại


107

Tôi có một ứng dụng web Spring Boot JPA nhỏ xinh. Nó được triển khai trên Amazon Beanstalk và sử dụng Amazon RDS để lưu trữ dữ liệu. Tuy nhiên, nó không được sử dụng thường xuyên và do đó không thành công sau một thời gian với loại ngoại lệ này:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Gói cuối cùng nhận được thành công từ máy chủ là 79,870,633 mili giây trước.
Gói cuối cùng được gửi thành công đến máy chủ là 79,870,634 mili giây trước. dài hơn giá trị được định cấu hình của máy chủ của 'wait_timeout'. Bạn nên cân nhắc việc sắp hết hạn và / hoặc kiểm tra tính hợp lệ của kết nối trước khi sử dụng trong ứng dụng của mình, tăng giá trị được cấu hình máy chủ cho thời gian chờ của máy khách hoặc sử dụng thuộc tính kết nối Connector / J 'autoReconnect = true' để tránh sự cố này.

Tôi không chắc về cách định cấu hình cài đặt này và không thể tìm thấy thông tin về cài đặt này trên http://spring.io (một trang web rất tốt). Một số ý tưởng hoặc con trỏ đến thông tin là gì?


Sử dụng cái này để in ra của bạn DataSourcevà xác minh các thuộc tính của nó. stackoverflow.com/a/36586630/148844 Spring Boot sẽ không tự động cấu hình DataSourcenếu bạn có bất kỳ @Beanscái nào xác định a DataSource. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/…
Chloe

Câu trả lời:


141

Tôi giả sử rằng khởi động đang định cấu hình DataSourcecho bạn. Trong trường hợp này, và vì bạn đang sử dụng MySQL, bạn có thể thêm phần sau vào application.propertiestối đa 1,3

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

Như djxak ghi nhận trong các bình luận, 1.4+ định nghĩa không gian tên cụ thể cho bốn kết nối hồ hỗ trợ mùa xuân Boot: tomcat, hikari, dbcp, dbcp2( dbcpbị phản đối như của 1.5). Bạn cần kiểm tra xem mình đang sử dụng nhóm kết nối nào và kiểm tra xem tính năng đó có được hỗ trợ hay không. Ví dụ trên là cho tomcat, vì vậy bạn phải viết nó như sau trong 1.4+:

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

Lưu ý rằng việc sử dụng autoReconnectđược không được khuyến khích :

Việc sử dụng tính năng này không được khuyến khích vì nó có các tác dụng phụ liên quan đến trạng thái phiên và tính nhất quán dữ liệu khi các ứng dụng không xử lý SQLExceptions đúng cách và chỉ được thiết kế để sử dụng khi bạn không thể định cấu hình ứng dụng của mình để xử lý SQLExceptions do kết nối chết và cũ đúng cách.


8
đó là bởi vì chúng tôi đã hài hòa cách chúng tôi viết khóa trong tài liệu. Chúng tôi luôn sử dụng một chất kết dính thoải mái để cả hai spring.datasource.testOnBorrowspring.datasource.test-on-borrowsẽ hoạt động tốt. Kiểm tra tài liệu để biết thêm chi tiết.
Stephane Nicoll

17
Vì nó có thể gây nhầm lẫn cho người khác: hãy SELECT 1đảm bảo rằng kết nối đã được kiểm tra trước khi nó được chuyển đến ứng dụng. Bằng cách sử dụng testOnBorrow = true, các đối tượng sẽ được xác nhận trước khi được mượn từ pool. Nếu đối tượng không được xác thực, nó sẽ bị loại khỏi nhóm và sẽ cố gắng mượn đối tượng khác. LƯU Ý - để một giá trị true có hiệu lực, tham số validationQuery phải được đặt thành một chuỗi không rỗng.
Rick

14
Cảnh báo! Trong mùa xuân Boot 1.4+ này đã được thay đổi : có được xác định không gian tên cụ thể mới cho bốn kết nối hồ hỗ trợ mùa xuân: tomcat, hikari, dbcp, dbcp2. Vì vậy, ví dụ, đối với nhóm tomcat-jdbckết nối, các thuộc tính phải là: spring.datasource.tomcat.testOnBorrow=truespring.datasource.tomcat.validationQuery=SELECT 1.
Ruslan Stelmachenko

1
Nếu tôi tự định cấu hình hai nguồn dữ liệu khác nhau thì làm cách nào để cung cấp những cấu hình này? Tôi có cần cung cấp cấu hình này cho cả nguồn dữ liệu như spring.datasource.mydatasource1.tomcat.testOnBorrow = true spring.datasource.mydatasource1.tomcat.validationQuery = SELECT 1 spring.datasource.mydatasource2.tomcat.testOnBorrow = true spring.datasource không. mydatasource2.tomcat.validationQuery = SELECT 1 Hoặc có điều gì khác để theo dõi ??
Nitish Kumar

2
Cảnh báo! Nếu bạn xác định bất kỳ DataSource @Bean nào trong ứng dụng của mình, thì Spring Boot sẽ không định cấu hình nhóm. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/… If you define your own DataSource bean, auto-configuration will not occur. Tôi đã làm theo hướng dẫn cho OAuth2 và có @Bean(name = "OAuth") public DataSource secondaryDataSource()...và nó không được tự động định cấu hình cũng như không sử dụng testOnBorrow.
Chloe

28

Những gợi ý trên đã không làm việc cho tôi. Điều thực sự hiệu quả là đưa các dòng sau vào ứng dụng.

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

Bạn có thể tìm thấy lời giải thích ở đây


5
Liên kết bạn đã thêm cho biết Nếu kết nối cơ sở dữ liệu không hoạt động trong hơn 8 giờ, nó sẽ tự động bị đóng và lỗi ở trên sẽ xảy ra. Vì vậy, giải pháp của bạn là không để kết nối không hoạt động trong thời gian dài hơn. Có cách nào tôi có thể kết nối với máy chủ SQL sau khi nó được khởi động lại không?
Akeshwar Jha

9

Cài đặt spring.datasource.tomcat.testOnBorrow=truetrong application.properties không hoạt động.

Cài đặt theo chương trình như bên dưới đã hoạt động mà không gặp bất kỳ sự cố nào.

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
Nếu bạn đang khai báo một nguồn dữ liệu tùy chỉnh thì có thể là do bạn đang cố sử dụng .tomcat mặc định của mùa xuân. Vì vậy, nếu bạn tạo một bean Datasource tùy chỉnh thì hãy thêm @ConfigurationProperties (prefix = "spring.datasource.tomcat") vào DataSource bean và sau đó nó sẽ cho phép bạn đặt chúng trong các thuộc tính ứng dụng. Ví dụ của tôi .. @Bean (name = "managementDataSource") @ConfigurationProperties (prefix = "management.datasource") public DataSource dataSource () {return DataSourceBuilder.create (). Build (); } management.datasource.test-on-loan = true
Justin

8

Tôi vừa chuyển sang Spring Boot 1.4 và thấy các thuộc tính này đã được đổi tên:

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

2
Các tên tương đương nhau. Xem phần về cách đặt tên thuộc tính trong tài liệu Spring Boot .
Stephen Harrison

@StephenHarrison: lưu ý tiền tố dbcp. * Được thêm vào 1.4, ràng buộc thoải mái không áp dụng trong trường hợp này.
YM

1
@Pawel: tùy thuộc vào việc triển khai gộp nào có sẵn trong dự án của bạn, nó có thể không phải là thuộc tính dbcp. * Dành cho bạn, hãy xem Khởi động mùa xuân với SQL và các thuộc tính Nguồn dữ liệu
YM

4

câu trả lời của whoami là một trong những chính xác. Sử dụng các thuộc tính như được đề xuất, tôi không thể làm cho điều này hoạt động (sử dụng Spring Boot 1.5.3.RELEASE)

Tôi đang thêm câu trả lời của mình vì đây là một lớp cấu hình hoàn chỉnh nên nó có thể giúp ích cho ai đó đang sử dụng 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;
    }
}

Bạn có biết tại sao cần mã tùy chỉnh này và tại sao Spring không chỉ đọc các thuộc tính này từ tệp thuộc tính không? Tôi có một số thuộc tính nguồn dữ liệu trong tệp của mình và nó đọc tất cả phần còn lại của chúng mà không có vấn đề gì.
Chú Tóc Dài,

3

Tôi có vấn đề tương tự. Spring 4 và Tomcat 8. Tôi giải quyết vấn đề với cấu hình 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>

Tôi đã thử rồi. Nó hoạt động tốt! Hai dòng này thực hiện mọi thứ để kết nối lại với cơ sở dữ liệu:

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

3

Trong trường hợp bất kỳ ai đang sử dụng DataSource tùy chỉnh

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

Thuộc tính sẽ giống như sau. Lưu ý @ConfigurationProperties với tiền tố. Tiền tố là mọi thứ trước tên thuộc tính thực tế

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

Tham chiếu cho Phiên bản mùa xuân 1.4.4. RELEASE


2

Như một số người đã chỉ ra, spring-boot 1.4+, có không gian tên cụ thể cho bốn nhóm kết nối. Theo mặc định, hikaricp được sử dụng trong spring-boot 2+. Vì vậy, bạn sẽ phải chỉ định SQL ở đây. Mặc định là SELECT 1. Đây là những gì bạn cần cho DB2 chẳng hạn: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

Lưu ý : Nếu trình điều khiển của bạn hỗ trợ JDBC4, chúng tôi đặc biệt khuyên bạn không nên đặt thuộc tính này. Điều này dành cho các trình điều khiển "kế thừa" không hỗ trợ API JDBC4 Connection.isValid (). Đây là truy vấn sẽ được thực hiện ngay trước khi một kết nối được cung cấp cho bạn từ nhóm để xác nhận rằng kết nối với cơ sở dữ liệu vẫn còn tồn tại. Một lần nữa, hãy thử chạy nhóm mà không có thuộc tính này, HikariCP sẽ ghi lại lỗi nếu trình điều khiển của bạn không tuân thủ JDBC4 để cho bạn biết. Mặc định: không có


0

Đối với những người muốn làm điều đó từ YAML với nhiều nguồn dữ liệu, có một bài đăng trên blog tuyệt vời về nó: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot -ứng dụng/

Về cơ bản, nó nói rằng bạn cần phải định cấu hình các thuộc tính nguồn dữ liệu và nguồn dữ liệu như sau:

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

Đừng quên xóa @Primarykhỏi các nguồn dữ liệu khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.