Spring 重试模板不适用于@org.springframework.transaction.annotation.Transactional
Spring retry template is not working with @org.springframework.transaction.annotation.Transactional
在数据库不可用的情况下,我需要重试执行我的服务方法3次。为此,我使用 Spring 重试模板。但是使用@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 框架级别,而不是在您的方法中,因此您的重试模板在这种情况下无用。
在第二种情况下,打开事务发生在重试范围内,因此重试捕获异常并且一切正常。
在数据库不可用的情况下,我需要重试执行我的服务方法3次。为此,我使用 Spring 重试模板。但是使用@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 框架级别,而不是在您的方法中,因此您的重试模板在这种情况下无用。
在第二种情况下,打开事务发生在重试范围内,因此重试捕获异常并且一切正常。