在数据库不可用的情况下,我需要重试执行我的服务方法3次。为此,我使用 Spring Retry Template。但是使用@Transactional注释,当数据库不可用时,无法捕获特定的异常。
@Configuration
public class RetryTemplateConfig {
@Bean
public RetryTemplate createRetryTemplate(){
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(5000l);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(5);
retryTemplate.setRetryPolicy(retryPolicy);
return retryTemplate;
}
}
@Service
public class MessageService {
@Autowired
private RetryTemplate retryTemplate;
@Autowired
MessageRepo messageRepo;
@Transactional
public void sendMessage(Message message) throws RuntimeException{
retryTemplate.execute(retryContext -> {
log.info("Executing for {} " , retryContext.getRetryCount());
Message model = new Message();
messageRepo.save(model);
return "";
});
}
}
但是,如果我在数据库不可用时尝试使用 @Retryable,则 RuntimeExcption 会成功重试,并在重试结束时调用 @Recover 方法。
@Service
@EnableRetry
public class MessageService {
@Autowired
private RetryTemplate retryTemplate;
@Autowired
MessageRepo messageRepo;
@Retryable(
value = {RuntimeException.class},
backoff = @Backoff(delay = 2000),
maxAttempts = 5
)
@Transactional
public void sendMessage(Message message) throws RuntimeException{
Message model = new Message();
messageRepo.save(model);
}
}
@Recover
public void recover(){
log.info("Recover is called ");
}
}
有人可以解释这两种不同行为的原因并建议我重试的最佳方法吗? (我正在使用 JPA 数据)
最佳答案
在第一种情况下,在使用 retryTemplate 时,即使在执行到达 retryTemplate.execute(...)
调用之前也会发生异常,因为 spring 无法打开您需要的事务( 通过@Transactional
注释,因为打开事务需要数据库连接),
因此异常发生在 spring 框架级别,而不是在您的方法中,因此您的重试模板在这种情况下毫无用处。
在第二种情况下,打开事务发生在重试范围内,因此重试捕获异常并且一切都很好。
关于Spring 重试模板不适用于 @org.springframework.transaction.annotation.Transactional,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57809431/