Leo*_*hra 21 mysql spring spring-boot hikaricp docker-compose
我有一个 docker-compose 设置来启动我的 SpringBoot 应用程序和一个 MySQL 数据库。如果数据库先启动,那么我的应用程序可以成功连接。但是如果我的应用程序先启动,还没有数据库存在,所以应用程序抛出以下异常并退出:
app_1 | 2018-05-27 14:15:03.415 INFO 1 --- [ main]
com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
app_1 | 2018-05-27 14:15:06.770 ERROR 1 --- [ main]
com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization
app_1 | com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
Communications link failure
Run Code Online (Sandbox Code Playgroud)
我可以编辑我的 docker-compose 文件以确保在应用程序启动之前数据库始终处于启动状态,但我希望应用程序能够自己处理这种情况,而不是在无法到达数据库地址时立即退出。
有多种方法可以在 application.properties 文件中配置数据源,以使应用程序重新连接到数据库,如此处和此处所述。但这不适用于到数据源的启动连接。
如何让我的 SpringBoot 应用程序在启动时以给定的时间间隔重试连接到数据库,直到它成功连接到数据库?
bre*_*ttw 20
将 HikariCP 的initializationFailTimeout属性设置为 0(零)或负数。如此处所述:
?
initializationFailTimeout此属性控制池是否会“快速失败”,如果池无法成功地设置初始连接的种子。任何正数都被视为尝试获取初始连接的毫秒数;在此期间,应用程序线程将被阻塞。如果在此超时发生之前无法获取连接,则会抛出异常。此超时被应用后的
connectionTimeout时期。如果该值为零 (0),HikariCP 将尝试获取并验证连接。如果获得了连接,但验证失败,则会抛出异常并且池不会启动。但是,如果无法获得连接,则池将启动,但稍后获得连接的努力可能会失败。小于零的值将绕过任何初始连接尝试,并且池将在尝试在后台获取连接时立即启动。因此,以后获得连接的努力可能会失败。默认值:1
有一种替代方法可以做到这一点,它不依赖于特定的连接池库或特定的数据库。请注意,您将需要使用spring-retry此方法来实现所需的行为
首先,您需要将 spring-retry 添加到您的依赖项中:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>${spring-retry.version}</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
然后你可以创建一个装饰器,DataSource它会像下面这样扩展AbstractDataSource:
@Slf4j
@RequiredArgsConstructor
public class RetryableDataSource extends AbstractDataSource {
private final DataSource dataSource;
@Override
@Retryable(maxAttempts = 5, backoff = @Backoff(multiplier = 1.3, maxDelay = 10000))
public Connection getConnection() throws SQLException {
log.info("getting connection ...");
return dataSource.getConnection();
}
@Override
@Retryable(maxAttempts = 5, backoff = @Backoff(multiplier = 2.3, maxDelay = 10000))
public Connection getConnection(String username, String password) throws SQLException {
log.info("getting connection by username and password ...");
return dataSource.getConnection(username, password);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要通过创建自定义的方法将此自定义 DataSource 装饰器注入到 Spring 上下文中BeanPostProcessor:
@Slf4j
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Component
public class RetryableDatabasePostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof DataSource) {
log.info("-----> configuring a retryable datasource for beanName = {}", beanName);
return new RetryableDataSource((DataSource) bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Run Code Online (Sandbox Code Playgroud)
最后但并非最不重要的一点是,您需要通过@EnableRetry向 spring 主类添加注释来启用 Spring 重试,例如:
@EnableRetry
@SpringBootApplication
public class RetryableDbConnectionApplication {
public static void main(String[] args) {
SpringApplication.run(RetryableDbConnectionApplication.class, args);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9325 次 |
| 最近记录: |