SpringBoot事务注解(二)

SpringBoot事务注解有哪些

1. @Transactional

这是Spring Boot里使用频率最高的事务注解,可用于类或者方法上。加在类上时,该类所有公共方法都会开启事务;加在方法上时,仅该方法开启事务。其常用属性如下:

  • propagation:指定事务传播行为,默认是 Propagation.REQUIRED
  • isolation:指定事务隔离级别,默认是 Isolation.DEFAULT
  • timeout:设定事务超时时间(单位为秒),默认 -1 表示无超时限制。
  • readOnly:指定事务是否为只读事务,默认 false
  • rollbackFor:指定哪些异常会触发事务回滚,默认仅 RuntimeExceptionError 会导致回滚。
  • noRollbackFor:指定哪些异常不会触发事务回滚。
2. @EnableTransactionManagement

此注解用于开启Spring的声明式事务管理功能。一般需添加到Spring Boot主应用类上,这样Spring才能识别 @Transactional 注解并开展事务管理工作。

3. @TransactionalEventListener

该注解用于在事务上下文中监听事件。使用此注解的方法会在事务完成后执行,可用于处理与事务相关的后续操作,例如发送通知、记录日志等。

Spring Boot中事务注解的原理

Spring Boot的事务注解依赖于Spring框架的AOP(面向切面编程)和事务管理机制来实现,具体原理如下:

1. 注解解析与AOP代理创建
  • @EnableTransactionManagement 的作用:在Spring Boot应用里,在主应用类添加 @EnableTransactionManagement 注解后,会触发Spring框架开启事务管理的自动配置。它会引入 TransactionManagementConfigurationSelector 类,该类会根据配置情况注册事务管理相关的Bean定义,其中重要的是注册 BeanFactoryTransactionAttributeSourceAdvisor 类型的切面(Advisor)。
  • 注解解析:Spring框架启动时会扫描所有带有 @Transactional 注解的类和方法。TransactionAttributeSource 接口负责解析 @Transactional 注解中的属性,将这些属性封装成 TransactionAttribute 对象,该对象包含事务的所有配置信息。
  • AOP代理创建:Spring会为带有 @Transactional 注解的Bean创建AOP代理,根据目标对象是否实现接口,可能使用JDK动态代理或CGLIB代理。代理对象会拦截目标方法的调用,在方法调用前后添加事务管理逻辑。
2. 事务拦截器的工作原理
  • TransactionInterceptor 拦截器BeanFactoryTransactionAttributeSourceAdvisor 切面包含 TransactionInterceptor 拦截器。当代理对象的方法被调用时,TransactionInterceptor 会进行拦截。
  • 获取事务属性TransactionInterceptorTransactionAttributeSource 中获取目标方法的 TransactionAttribute 对象,依据该对象的配置信息管理事务。
  • 事务的开启、提交和回滚
    • 开启事务:根据 TransactionAttribute 中的传播行为和隔离级别,TransactionInterceptor 调用 PlatformTransactionManager 开启新事务或加入已有事务。PlatformTransactionManager 是Spring提供的事务管理器接口,不同数据库和持久化框架有不同实现。
    • 方法执行:事务开启后,TransactionInterceptor 调用目标对象的实际方法执行具体业务逻辑。
    • 提交事务:若目标方法正常执行完毕,未抛出异常,TransactionInterceptor 根据 TransactionAttribute 配置,调用 PlatformTransactionManager 提交事务。
    • 回滚事务:若目标方法抛出异常,TransactionInterceptor 根据 @Transactional 注解中的 rollbackFornoRollbackFor 属性判断是否回滚事务,若需要则调用 PlatformTransactionManager 执行回滚操作。

举例说明Spring Boot中事务注解的传播行为

假设存在两个服务类 ServiceAServiceBServiceA 调用 ServiceB 的方法,且这些方法都添加了 @Transactional 注解。以下是相关代码及不同传播行为的示例:

ServiceA.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ServiceA {

    @Autowired
    private ServiceB serviceB;

    @Transactional
    public void methodA() {
        // 模拟业务逻辑
        System.out.println("ServiceA.methodA() 开始执行");
        serviceB.methodB();
        System.out.println("ServiceA.methodA() 执行结束");
    }
}
ServiceB.java
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ServiceB {

    // 1. Propagation.REQUIRED
    @Transactional(propagation = Propagation.REQUIRED)
    public void methodBRequired() {
        System.out.println("ServiceB.methodBRequired() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBRequired() 执行结束");
    }

    // 2. Propagation.REQUIRES_NEW
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void methodBRequiresNew() {
        System.out.println("ServiceB.methodBRequiresNew() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBRequiresNew() 执行结束");
    }

    // 3. Propagation.NESTED
    @Transactional(propagation = Propagation.NESTED)
    public void methodBNested() {
        System.out.println("ServiceB.methodBNested() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBNested() 执行结束");
    }

    // 4. Propagation.SUPPORTS
    @Transactional(propagation = Propagation.SUPPORTS)
    public void methodBSupports() {
        System.out.println("ServiceB.methodBSupports() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBSupports() 执行结束");
    }

    // 5. Propagation.MANDATORY
    @Transactional(propagation = Propagation.MANDATORY)
    public void methodBMandatory() {
        System.out.println("ServiceB.methodBMandatory() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBMandatory() 执行结束");
    }

    // 6. Propagation.NOT_SUPPORTED
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void methodBNotSupported() {
        System.out.println("ServiceB.methodBNotSupported() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBNotSupported() 执行结束");
    }

    // 7. Propagation.NEVER
    @Transactional(propagation = Propagation.NEVER)
    public void methodBNever() {
        System.out.println("ServiceB.methodBNever() 开始执行");
        // 模拟可能的异常
        // if (true) {
        //     throw new RuntimeException("模拟异常");
        // }
        System.out.println("ServiceB.methodBNever() 执行结束");
    }
}
不同传播行为的效果
  • Propagation.REQUIREDServiceA.methodA() 调用 ServiceB.methodBRequired() 时,由于 methodA() 已开启事务,methodBRequired() 会加入该事务。若 methodBRequired() 抛出异常,整个事务都会回滚。
  • Propagation.REQUIRES_NEWServiceA.methodA() 调用 ServiceB.methodBRequiresNew() 时,methodBRequiresNew() 会创建新事务,与 methodA() 的事务相互独立。若 methodBRequiresNew() 抛出异常,仅回滚 methodBRequiresNew() 的事务,methodA() 的事务不受影响。
  • Propagation.NESTEDServiceA.methodA() 调用 ServiceB.methodBNested() 时,methodBNested() 会在 methodA() 的事务内部创建嵌套事务。若 methodBNested() 抛出异常,仅回滚 methodBNested() 的嵌套事务,methodA() 的事务可选择是否继续提交。
  • Propagation.SUPPORTSServiceA.methodA() 调用 ServiceB.methodBSupports() 时,因 methodA() 有事务,methodBSupports() 会加入该事务。若 methodA() 未开启事务,methodBSupports() 会以非事务方式执行。
  • Propagation.MANDATORYServiceA.methodA() 调用 ServiceB.methodBMandatory() 时,methodBMandatory() 会加入 methodA() 的事务。若 methodA() 未开启事务,调用 methodBMandatory() 会抛出异常。
  • Propagation.NOT_SUPPORTEDServiceA.methodA() 调用 ServiceB.methodBNotSupported() 时,methodBNotSupported() 会以非事务方式执行,同时挂起 methodA() 的事务。methodBNotSupported() 执行完毕后,methodA() 的事务继续执行。
  • Propagation.NEVERServiceA.methodA() 调用 ServiceB.methodBNever() 时,由于 methodA() 有事务,调用 methodBNever() 会抛出异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值