Spring Boot JPA - การกำหนดค่าการเชื่อมต่อใหม่อัตโนมัติ


107

ฉันมีเว็บแอปพลิเคชั่น 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 (เป็นเว็บไซต์ที่ดีมาก) มีแนวคิดหรือตัวชี้ข้อมูลอะไรบ้าง?


ใช้สิ่งนี้เพื่อพิมพ์DataSourceและตรวจสอบคุณสมบัติของคุณ stackoverflow.com/a/36586630/148844 Spring Boot จะไม่กำหนดค่าอัตโนมัติDataSourceหากคุณมีสิ่งใด@Beansที่กำหนดไฟล์DataSource. docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/…
Chloe

คำตอบ:


141

ฉันคิดว่าการบูตกำลังกำหนดค่าDataSourceให้คุณ ในกรณีนี้และเนื่องจากคุณใช้ MySQL คุณสามารถเพิ่มสิ่งต่อไปนี้application.propertiesลงใน 1.3 ได้สูงสุด

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

ในฐานะที่เป็น djxak ตั้งข้อสังเกตในความคิดเห็นที่ 1.4+ กำหนด namespaces ที่เฉพาะเจาะจงสำหรับสี่สระว่ายน้ำการเชื่อมต่อฤดูใบไม้ผลิ Boot สนับสนุน: tomcat, hikari, dbcp, dbcp2( dbcpเลิกเป็น 1.5) คุณต้องตรวจสอบว่าคุณใช้พูลการเชื่อมต่อใดและตรวจสอบว่าคุณสมบัตินั้นได้รับการสนับสนุนหรือไม่ ตัวอย่างด้านบนเป็นของ Tomcat ดังนั้นคุณต้องเขียนดังนี้ใน 1.4+:

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

โปรดทราบว่าการใช้autoReconnectจะไม่แนะนำ :

ไม่แนะนำให้ใช้คุณลักษณะนี้เนื่องจากมีผลข้างเคียงที่เกี่ยวข้องกับสถานะเซสชันและความสอดคล้องของข้อมูลเมื่อแอปพลิเคชันไม่จัดการ SQLExceptions อย่างเหมาะสมและได้รับการออกแบบมาให้ใช้เฉพาะเมื่อคุณไม่สามารถกำหนดค่าแอปพลิเคชันของคุณให้จัดการ SQLExceptions ที่เป็นผลมาจาก การเชื่อมต่อที่ตายแล้วและเก่าอย่างถูกต้อง


8
นั่นเป็นเพราะเราได้ประสานวิธีการเขียนคีย์ในเอกสาร เรามักจะใช้ผ่อนคลายเครื่องผูกเพื่อให้ทั้งสองspring.datasource.testOnBorrowและspring.datasource.test-on-borrowจะทำงานได้ดี ตรวจสอบเอกสารสำหรับรายละเอียดเพิ่มเติม
Stephane Nicoll

17
เนื่องจากอาจทำให้ผู้อื่นสับสน: SELECT 1รับประกันว่าการเชื่อมต่อได้รับการทดสอบก่อนที่จะส่งไปยังแอปพลิเคชัน โดยการใช้testOnBorrow = trueงานวัตถุจะได้รับการตรวจสอบความถูกต้องก่อนที่จะถูกยืมออกจากสระว่ายน้ำ หากตรวจสอบความถูกต้องไม่สำเร็จวัตถุนั้นจะถูกทิ้งจากสระและจะพยายามยืมตัวอื่น หมายเหตุ - เพื่อให้ค่าที่แท้จริงมีผลใด ๆ พารามิเตอร์ validationQuery ต้องถูกตั้งค่าเป็นสตริงที่ไม่เป็นค่าว่าง
Rick

14
คำเตือน! ในฤดูใบไม้ผลิ Boot 1.4+ นี้ที่เปลี่ยนไป : มีการกำหนด namespaces tomcatเฉพาะใหม่สำหรับสระว่ายน้ำการเชื่อมต่อสี่ฤดูใบไม้ผลิสนับสนุน: hikari, dbcp, dbcp2, ตัวอย่างเช่นสำหรับtomcat-jdbcพูลการเชื่อมต่อคุณสมบัติควรเป็น: spring.datasource.tomcat.testOnBorrow=trueและspring.datasource.tomcat.validationQuery=SELECT 1.
Ruslan Stelmachenko

1
ถ้าฉันกำลังกำหนดค่าแหล่งข้อมูลที่แตกต่างกันสองแหล่งฉันจะให้การกำหนดค่าเหล่านี้ได้อย่างไร ฉันต้องจัดเตรียมการกำหนดค่านี้สำหรับทั้งแหล่งข้อมูลเช่น 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 หรือมีอย่างอื่นตามมา ??
Nitish Kumar

2
คำเตือน! หากคุณกำหนด DataSource @Bean ในแอปของคุณ Spring Boot จะไม่กำหนดค่าพูล docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/... If you define your own DataSource bean, auto-configuration will not occur.ผมทำตามคำแนะนำสำหรับ OAuth2 และมีและมันก็ไม่ได้กำหนดค่าโดยอัตโนมัติมิได้ใช้@Bean(name = "OAuth") public DataSource secondaryDataSource()... testOnBorrow
Chloe

28

คำแนะนำข้างต้นไม่ได้ผลสำหรับฉัน สิ่งที่ได้ผลจริงคือการรวมบรรทัดต่อไปนี้ไว้ใน application.properties

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

คุณสามารถค้นหาคำอธิบายได้ที่นี่


5
ลิงก์ที่คุณเพิ่มระบุว่าหากการเชื่อมต่อฐานข้อมูลไม่ได้ใช้งานนานกว่า 8 ชั่วโมงระบบจะปิดโดยอัตโนมัติและข้อผิดพลาดข้างต้นจะเกิดขึ้น ดังนั้นวิธีแก้ปัญหาของคุณคืออย่าปล่อยให้การเชื่อมต่อไม่ได้ใช้งานเป็นเวลานาน มีวิธีเชื่อมต่อกับเซิร์ฟเวอร์ SQL หลังจากรีสตาร์ทแล้วหรือไม่?
Akeshwar Jha

9

การตั้งค่าspring.datasource.tomcat.testOnBorrow=trueใน application.properties ไม่ทำงาน

การตั้งค่าโดยใช้โปรแกรมเหมือนด้านล่างทำงานได้โดยไม่มีปัญหาใด ๆ

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
หากคุณกำลังประกาศแหล่งข้อมูลแบบกำหนดเองอาจเป็นเพราะคุณกำลังพยายามใช้สปริงดีฟอลต์. Tomcat ดังนั้นหากคุณสร้าง Datasource bean แบบกำหนดเองให้เพิ่ม @ConfigurationProperties (คำนำหน้า = "spring.datasource.tomcat") ไปยัง DataSource bean จากนั้นควรอนุญาตให้คุณตั้งค่าในคุณสมบัติของแอปพลิเคชัน ตัวอย่างของฉัน .. @Bean (name = "managementDataSource") @ConfigurationProperties (prefix = "management.datasource") dataSource dataSource สาธารณะ () {return DataSourceBuilder.create (). build (); } management.datasource.test-on-loan = true
Justin

8

ฉันเพิ่งย้ายไปที่ 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

2
ชื่อเทียบเท่ากัน ดูส่วนที่เกี่ยวกับการตั้งชื่อสถานที่ให้บริการในเอกสารฤดูใบไม้ผลิ Boot
Stephen Harrison

@StephenHarrison: สังเกตคำนำหน้า dbcp. * ที่เพิ่มใน 1.4 การผูกแบบผ่อนคลายจะไม่ใช้ในกรณีนี้
YM

1
@Pawel: ขึ้นอยู่กับการใช้งานแบบพูลที่พร้อมใช้งานในโปรเจ็กต์ของคุณอาจไม่ใช่คุณสมบัติ dbcp. * สำหรับคุณดูSpring boot ด้วย SQLและคุณสมบัติ Datasource ที่
YM

4

คำตอบของ 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 จึงไม่เพียงอ่านคุณสมบัติเหล่านี้จากไฟล์คุณสมบัติ ฉันมีคุณสมบัติแหล่งข้อมูลหลายอย่างในไฟล์ของฉันและมันอ่านส่วนที่เหลือทั้งหมดโดยไม่มีปัญหา
ลุงผมยาว

3

ฉันมีปัญหาที่คล้ายกัน Spring 4 และ Tomcat 8 ฉันแก้ปัญหาด้วย Spring configuration

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

3

ในกรณีที่ใครก็ตามกำลังใช้ DataSource ที่กำหนดเอง

@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 รีลีส


2

ตามที่บางคนกล่าวไปแล้ว spring-boot 1.4+ มีเนมสเปซเฉพาะสำหรับพูลการเชื่อมต่อทั้งสี่ โดยค่าเริ่มต้น hikaricp จะใช้ใน spring-boot 2+ ดังนั้นคุณจะต้องระบุ SQL ที่นี่ SELECT 1เริ่มต้นคือ นี่คือสิ่งที่คุณต้องการสำหรับ DB2 เช่น: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

Caveat : หากไดรเวอร์ของคุณรองรับ JDBC4 เราขอแนะนำอย่างยิ่งว่าอย่าตั้งค่าคุณสมบัตินี้ สำหรับไดรเวอร์ "ดั้งเดิม" ที่ไม่รองรับ JDBC4 Connection.isValid () API นี่คือแบบสอบถามที่จะดำเนินการก่อนที่จะให้การเชื่อมต่อกับคุณจากพูลเพื่อตรวจสอบว่าการเชื่อมต่อกับฐานข้อมูลยังคงมีชีวิตอยู่ อีกครั้งลองรันพูลโดยไม่มีคุณสมบัตินี้ HikariCP จะบันทึกข้อผิดพลาดหากไดรเวอร์ของคุณไม่สอดคล้องกับ JDBC4 เพื่อแจ้งให้คุณทราบ ค่าเริ่มต้น: ไม่มี


0

สำหรับผู้ที่ต้องการทำจาก YAML ที่มีแหล่งข้อมูลหลายแหล่งมีบล็อกโพสต์ที่ยอดเยี่ยมเกี่ยวกับเรื่องนี้: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot - ใบสมัคร /

โดยพื้นฐานแล้วบอกว่าคุณต้องกำหนดค่าคุณสมบัติของแหล่งข้อมูลและแหล่งข้อมูลดังนี้:

@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จากแหล่งข้อมูลอื่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.