首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Spring @Retryable 与 @Transactional 结合使用(注意 aop 的执行顺序)

Spring @Retryable 与 @Transactional 结合使用(注意 aop 的执行顺序)

作者头像
nobody-nobody
发布2026-03-16 21:15:38
发布2026-03-16 21:15:38
850
举报
文章被收录于专栏:nobodynobody

在企业级应用中,重试数据库操作是一项必要功能,特别是在处理临时性问题(如死锁、瞬时连接故障、竞争条件或短暂的服务中断)时。Spring 提供了使用声明式注解(如 @Retryable@Transactional 结合)以及基于 RetryTemplateTransactionTemplate 的完全编程式方法来实现可靠重试的机制。

这两种方法都必须确保每次重试都在自己的事务中执行,因为在单个事务内执行多次重试尝试可能会导致立即失败。这是因为早期的异常可能会将事务标记为仅回滚状态,导致所有剩余尝试都失败,即使它们本可以成功

本文解释了 Spring Retry 如何与事务性方法一起工作,并演示了基于注解和编程式方法来实现可靠重试。

1. 在项目中添加 Spring Retry

要使用 Spring Retry,请在 pom.xml 中包含必要的依赖项:

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>2.0.12</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>

2. 在应用程序中启用 Spring Retry

使用 @EnableRetry 注解启用 Spring Retry。order 值确定重试拦截器相对于 Spring 事务拦截器的优先级。将其设置为最低优先级可确保重试建议包装事务建议,这对于将每次重试隔离到其自己的新事务中至关重要

代码语言:javascript
复制
@Configuration
@EnableRetry(order = Ordered.LOWEST_PRECEDENCE)
public class RetryConfig {
}

此设置确保重试逻辑首先激活。当发生重试时,Spring 会退出前一个事务,再次调用方法,并为新尝试启动一个新事务

实现重试的一种解决方案是将 Spring 的 AOP 支持的@Retryable注解与@Transactional注解相结合。在这种模式中,重试机制包装了事务边界,以便每次重试尝试都在一个干净、独立的事务中执行

代码语言:javascript
复制
@Retryable(
    maxAttempts = 3,
    backoff = @Backoff(delay = 2000)
)
@Transactional
public void processPayment(double amount) {
    logger.log(Level.INFO, "Attempt #: {0}", attempt);

    Payment payment = new Payment("PENDING", amount);
    paymentRepository.save(payment);

    // 模拟前两次尝试的瞬时异常
    if (attempt < 3) {
        attempt++;
        thrownew RuntimeException("模拟瞬时故障");
    }

    payment.setStatus("SUCCESS");
    paymentRepository.save(payment);
    logger.log(Level.INFO, "Payment processed successfully on attempt #: {0}", attempt);
}

在此示例中,前两次尝试通过抛出异常故意失败。由于重试建议在事务建议之外应用,Spring 会安全地回滚每次失败的尝试,然后触发新的调用,每次都开始一个新的事务。当方法到达第三次尝试时,早期尝试的失败标志不再影响它。第三次尝试在干净的事务内运行并成功进行。

4. 使用 RetryTemplate 和 TransactionTemplate 进行编程式重试

某些用例需要对重试策略、错误分类和事务边界进行更精细的控制。在这种情况下,使用 RetryTemplateTransactionTemplate编程式方法提供了对重试时机、异常处理和事务执行的更精细控制

代码语言:javascript
复制
@Service
publicclass PaymentServiceProgrammatic {

    privatestaticfinal Logger logger = Logger.getLogger(PaymentServiceProgrammatic.class.getName());

    privatefinal PaymentRepository paymentRepository;
    privatefinal TransactionTemplate transactionTemplate;

    public PaymentServiceProgrammatic(PaymentRepository paymentRepository, TransactionTemplate transactionTemplate) {
        this.paymentRepository = paymentRepository;
        this.transactionTemplate = transactionTemplate;
    }

    privatefinal RetryTemplate retryTemplate = new RetryTemplateBuilder()
            .maxAttempts(3)
            .fixedBackoff(Duration.ofMillis(100))
            .build();

    public void processPayment(double amount) {

        retryTemplate.execute(context -> {
            logger.info("Retry attempt: " + context.getRetryCount());
            // 在手动控制的事务内执行操作
            return transactionTemplate.execute(status -> {

                Payment payment = new Payment("PENDING", amount);
                paymentRepository.save(payment);
                // 演示模拟瞬时故障
                if (context.getRetryCount() < 3) {
                    thrownew RuntimeException("模拟瞬时故障");
                }
                payment.setStatus("SUCCESS");
                paymentRepository.save(payment);
                logger.info("Payment processed successfully on retry attempt: " + context.getRetryCount());

                returnnull;
            });
        });
    }
}

此示例使用 RetryTemplate 自动检测故障,最多重试三次,固定退避 100ms,并提供对重试上下文的访问,包括当前尝试次数,而 TransactionTemplate确保每次重试都在新的、隔离的事务内执行,在失败时正确回滚,并防止任何部分提交的结果

5. 结论

在本文中,我们探讨了如何使用声明式和编程式方法在 Spring 中实现可靠的事务性重试。我们演示了 @Retryable 与 @Transactional 结合如何实现干净、基于注解的重试,以及 RetryTemplate 与 TransactionTemplate 如何提供对事务边界、重试策略和退避策略的完全控制。通过确保每次重试在新事务内执行,这些策略可防止来自先前失败的回滚副作用,并保证一致、确定的结果。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 在项目中添加 Spring Retry
  • 2. 在应用程序中启用 Spring Retry
  • 4. 使用 RetryTemplate 和 TransactionTemplate 进行编程式重试
  • 5. 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档