数据库宕机时Spring-Data-JPA登录失败,多数据源Spring Batch连接重试问题求助
Spring Batch多数据源午夜连接重试问题解决方案
方案1:调整连接池重试间隔
Spring Boot默认使用HikariCP连接池,针对会停机的数据源单独调整连接池参数即可拉长重试间隔,同时避免服务启动时强制校验连接:
- 核心参数说明:
initialization-fail-timeout设为-1:服务启动时即使对应数据库不可用也不会报错,不会强制初始化连接connection-timeout:调整客户端等待可用连接的最大时长,按需拉长即可idle-timeout:拉长空闲连接存活时长,避免服务运行过程中频繁探测不可用的数据库
- 配置示例:
spring: datasource: target-db: # 替换为你会夜间停机的数据源配置前缀 jdbc-url: jdbc:mysql://xx:3306/xx username: root password: xxx driver-class-name: com.mysql.cj.jdbc.Driver hikari: initialization-fail-timeout: -1 connection-timeout: 60000 # 连接等待超时调整为60秒,默认30秒 validation-timeout: 30000 idle-timeout: 3600000 # 空闲连接1小时后才释放 max-lifetime: 7200000
方案2:配置独立懒加载EntityManager实现按需建连
完全可以为每个数据源配置独立的EntityManager,加上懒加载注解后只有第一次执行对应数据源的查询时才会初始化连接,完美避开午夜数据库停机的时间段:
- 把不同数据源对应的实体类、Repository接口拆分到不同的包下,避免扫描冲突
- 分别为每个数据源编写独立的配置类,核心是给EntityManagerFactory加上
@Lazy注解 - 代码示例:
// 正常运行的数据源配置类 @Configuration @EnableJpaRepositories( basePackages = "com.xxx.repository.normal", // 对应数据源的Repository包路径 entityManagerFactoryRef = "normalEntityManagerFactory", transactionManagerRef = "normalTransactionManager" ) public class NormalDataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.normal") public DataSource normalDataSource() { return DataSourceBuilder.create().build(); } @Bean public LocalContainerEntityManagerFactoryBean normalEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("normalDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.xxx.entity.normal") // 对应数据源的实体类包路径 .persistenceUnit("normal") .build(); } @Bean public PlatformTransactionManager normalTransactionManager( @Qualifier("normalEntityManagerFactory") LocalContainerEntityManagerFactoryBean factory) { return new JpaTransactionManager(Objects.requireNonNull(factory.getObject())); } }
// 会夜间停机的数据源配置类 @Configuration @EnableJpaRepositories( basePackages = "com.xxx.repository.target", entityManagerFactoryRef = "targetEntityManagerFactory", transactionManagerRef = "targetTransactionManager" ) public class TargetDataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.target") public DataSource targetDataSource() { return DataSourceBuilder.create().build(); } @Bean @Lazy // 核心:仅第一次调用该数据源的Repository时才会初始化连接 public LocalContainerEntityManagerFactoryBean targetEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("targetDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.xxx.entity.target") .persistenceUnit("target") .build(); } @Bean public PlatformTransactionManager targetTransactionManager( @Qualifier("targetEntityManagerFactory") LocalContainerEntityManagerFactoryBean factory) { return new JpaTransactionManager(Objects.requireNonNull(factory.getObject())); } }
配置完成后,服务启动时不会初始化夜间停机的数据源的连接池,只有每天上午7点任务运行、第一次调用对应数据源的Repository时才会尝试建连,此时数据库已经完成清理恢复服务,不会再出现频繁重试失败的问题。如果7点任务运行时仍可能碰到数据库未恢复的场景,可以配合Spring Batch的Step重试机制,给对应任务步骤配置重试次数和重试间隔即可。
内容的提问来源于stack exchange,提问作者Rishi
相关产品推荐
相关产品推荐

