【问题标题】:Spring Boot JPA - configuring auto reconnectSpring Boot JPA - 配置自动重新连接
【发布时间】:2014-05-06 06:15:24
【问题描述】:

我有一个不错的小型 Spring Boot JPA Web 应用程序。它部署在 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 上找到有关它的信息(虽然是一个非常好的网站)。有哪些想法或信息指针?

【问题讨论】:

标签: spring spring-boot configuration


【解决方案1】:

对于那些想通过 YAML 使用多个数据源进行操作的人,有一篇很棒的博客文章:https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot-application/

它基本上说你需要像这样配置数据源属性和数据源:

@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

【讨论】:

    【解决方案2】:

    正如一些人已经指出的那样,spring-boot 1.4+ 具有四个连接池的特定命名空间。默认情况下,在 spring-boot 2+ 中使用 hikaricp。因此,您必须在此处指定 SQL。默认值为SELECT 1。例如,以下是 DB2 所需要的: spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

    Caveat:如果您的驱动程序支持 JDBC4,我们强烈建议您不要设置此属性。这适用于不支持 JDBC4 Connection.isValid() API 的“旧版”驱动程序。这是将在池中为您提供连接之前执行的查询,以验证与数据库的连接是否仍然存在。同样,尝试在没有此属性的情况下运行池,如果您的驱动程序不符合 JDBC4,HikariCP 将记录错误以通知您。默认值:无

    【讨论】:

      【解决方案3】:

      whoami's answer 是正确的。使用建议的属性我无法让它工作(使用 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 不会从属性文件中读取这些属性吗?我的文件中有几个数据源属性,它可以毫无问题地读取其余所有属性。
      【解决方案4】:

      如果有人使用自定义数据源

      @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.RELEASE 参考

      【讨论】:

        【解决方案5】:

        在 application.properties 中设置 spring.datasource.tomcat.testOnBorrow=true 不起作用。

        像下面这样以编程方式设置没有任何问题。

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

        【讨论】:

        • 如果您要声明自定义数据源,可能是因为您尝试使用 spring 默认的 .tomcat。因此,如果您创建自定义 Datasource bean,然后将 @ConfigurationProperties(prefix = "spring.datasource.tomcat") 添加到 DataSource bean,然后它应该允许您在应用程序属性中设置它们。我的例子.. @Bean(name = "managementDataSource") @ConfigurationProperties(prefix = "management.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } management.datasource.test-on-borrow=true
        【解决方案6】:

        我刚搬到 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
        

        【讨论】:

        • 名称是等价的。请参阅Spring Boot docs 中有关属性命名的部分。
        • @StephenHarrison :请注意 1.4 中添加的 dbcp.* 前缀,宽松绑定在这种情况下不适用。
        • @Pawel :根据您的项目中可用的池实现,它可能不是您的 dbcp.* 属性,请参阅Spring boot with SQL 和相应的Datasource properties
        【解决方案7】:

        我假设 boot 正在为您配置 DataSource。在这种情况下,由于您使用的是 MySQL,您可以将以下内容添加到您的 application.properties 最高 1.3

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

        正如 djxak 在评论中指出的那样,1.4+ 为 Spring Boot 支持的四个连接池定义了特定的命名空间:tomcathikaridbcpdbcp2dbcp 自 1.5 起已弃用)。您需要检查您正在使用的连接池并检查该功能是否受支持。上面的例子是针对 tomcat 的,所以你必须在 1.4+ 中编写如下:

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

        注意autoReconnect的使用是not recommended

        不建议使用此功能,因为当应用程序无法正确处理 SQLExceptions 时,它会产生与会话状态和数据一致性相关的副作用,并且仅设计为在您无法配置应用程序处理时使用由死连接和陈旧连接正确导致的 SQLExceptions。

        【讨论】:

        • 那是因为我们已经协调了我们在文档中编写密钥的方式。我们总是使用 relaxed 活页夹,所以spring.datasource.testOnBorrowspring.datasource.test-on-borrow 都可以正常工作。更多详情请查看the documentation
        • 因为它可能会使其他人感到困惑:SELECT 1 保证连接在传递给应用程序之前已经过测试。通过使用testOnBorrow = true,对象将在从池中借用之前进行验证。如果对象验证失败,它将从池中删除,并尝试借用另一个。注意 – 要使真值生效,validationQuery 参数必须设置为非空字符串。
        • 警告! 在 Spring Boot 1.4+ 中这是 changed:为 spring 支持的四个连接池定义了新的特定命名空间:tomcathikaridbcpdbcp2。因此,例如,对于 tomcat-jdbc 连接池,属性应该是:spring.datasource.tomcat.testOnBorrow=truespring.datasource.tomcat.validationQuery=SELECT 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 或者还有什么要遵循的??
        • 警告!如果您在应用程序中定义任何 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
        【解决方案8】:

        以上建议对我不起作用。 真正起作用的是在 application.properties 中包含以下几行

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

        你可以找到解释here

        【讨论】:

        • 你添加的链接说如果数据库连接超过8小时不活动,它会自动关闭,并且会发生上述错误。所以,你的解决方案不是让连接在较长时间内保持不活动状态。有什么方法可以在重启后连接到 SQL 服务器?
        • 根据 MySQL 文档超时,是否可以设置 28,800,000-1 而不是 3,600,000 以避免超时?
        【解决方案9】:

        我也有类似的问题。 Spring 4 和 Tomcat 8。我用 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>
        

        我已经测试过了。它运作良好!这两行做了所有事情以重新连接到数据库:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-06-05
          • 1970-01-01
          • 2018-11-21
          • 1970-01-01
          • 2017-01-26
          • 2019-11-28
          • 1970-01-01
          相关资源
          最近更新 更多