Spring 之 @Transaction 详解

介绍

@Transaction 是 Spring 提供用来控制事务回滚/提交的一个注解,让我们从编程式注解转换到声明式注解。在这里就不做过多的撰述,今天主要来看下 @Transaction 里面的属性使用。

作用域

@Transaction 可以写在类、接口、方法上

  • 当标注在类上的时候:表示给该类所有的 public 方法添加上 @Transaction 注解
  • 当标注在接口上的时候:Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。像 CGLib 动态代理采用继承的方式将会导致 @Transactional 注解失效
  • 当标注在方法上的时候:事务的作用域就只在该方法上生效,并且如果类及方法上都配置 @Transaction 注解时,方法的注解会覆盖类上的注解

属性

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

可以看到 @Transaction 相关所有的属性值

字段名类型含义
valueString主要用来指定不同的事务管理器
满足在同一个系统中,存在不同的事务管理器
propagationenum: Propagation可选的事务传播行为设置
isolationenum: Isolation可选的事务隔离级别设置
readOnlyboolean读写或只读事务,默认读写
timeoutint (in seconds granularity)事务超时时间设置
rollbackForClass对象数组,必须继承自Throwable导致事务回滚的异常类数组
rollbackForClassName类名数组,必须继承自Throwable导致事务回滚的异常类名字数组
noRollbackForClass对象数组,必须继承自Throwable不会导致事务回滚的异常类数组
noRollbackForClassName类名数组,必须继承自Throwable不会导致事务回滚的异常类名字数组

value

value 主要用来指定不同的事务管理器,满足在同一个系统中,存在不同的事务管理器。如果在 Spring 中,配置了多个数据源声明了多个事务管理器,可以通过该参数来进行指定事务管理器。

propagation

事务传播行为有一下7种,默认是 REQUIRED 传播机制。

含义
REQUIRED

如果当前存在事务,则加入该事务;

如果当前不存在事务,则创建一个新的事务;

SUPPORTS

如果当前存在事务,则加入该事务;

如果当前不存在事务,则以非事务的方式继续运行;

MANDATORY

如果当前存在事务,则加入该事务;

如果当前不存在事务,则抛出异常;

REQUIRES_NEW

如果当前不存在事务,重新创建一个新的事务;

如果当前存在事务,则暂停当前的事务;

NOT_SUPPORTED

以非事务的方式运行

如果当前存在事务,则暂停当前的事务

NEVER

以非事务的方式运行

如果当前存在事务,则抛出异常

NESTED

如果当前存在事务,则在该事务内嵌套事务运行;

如果当前不存在事务,则创建一个新的事务;

这里比较容易引起疑问的是 REQUIRED 和 NESTED 有什么差别?也是面试的重灾区。

@Service
public class ServiceA{
    @Autowired
    private ServiceB serviceB;
    
    @Transaction
    public void A(){
        try{
            serviceB.B();
        }catch(Exception e){
            e.printStackTrace();
        } 
        //伪代码,执行数据库修改操作
    }
}
@Service
public class ServiceB{
    
    @Transaction(propagation = Propagation.REQUIRED)
    public void B(){
        //伪代码,执行数据库修改操作
    }
}

如上存在 ServiceA、ServiceB 两个类和A、B两个方法(这里指的异常都是 RuntimeException 异常或其子类)

  • 情况一:A方法中出现了异常,结果A、B方法修改操作都会被回滚
  • 情况二:B方法中出现了异常,结果A、B方法修改操作都会被回滚
@Service
public class ServiceB{
    
    @Transaction(propagation = Propagation.NESTED)
    public void B(){
        //伪代码,执行数据库修改操作
    }
}

接下来将B方法的 propagation 修改为 NESTED 事务传播机制

  • 情况一:A方法中出现了异常,结果A、B方法修改操作都会被回滚
  • 情况二:B方法中出现了异常,结果B方法修改操作被回滚,A方法修改操作提交

通过如上案例,希望可以帮助大家掌握这两个事务传播机制的差异。

isolation

isolation 对应的事务隔离级别与 MySQL 一致,有不熟悉的同学可以另外了解一下。主要用来避免脏读、不可重复读以及幻读的问题。

 

readOnly

设置为 true:表示只读,如果该方法内存在增、删、改操作则会抛出异常;

设置为false(默认):表示读写,增、删、改、查操作都允许;

rollbackFor 和 rollbackForClassName

这两个属性都是用来指定回滚的异常类型

  • rollbackFor:通过类进行指定,如@Transactional(rollbackFor = {Exception.class})
  • rollbackForClassName:通过类名进行指定,如@Transactional(rollbackForClassName = {"java.lang.Exception"})

可能有同学会有疑问,为什么需要知道回滚的异常类型呢?不是默认有异常就回滚嘛?

Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor 或者 rollbackForClassName 属性。

noRollbackFor 和 noRollbackForClassName

与 rollbackFor 和 rollbackForClassName 相反,是用来指定不回滚的异常类型,使用方法一致。

手动回滚

spring 也提供了 @Transaction 对应的手动回滚方式

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

如果在代码中一定要 catch 住异常记得使用手动回滚的方式或者重新抛出一个异常。

失效场景

接下来看一下场景的 @Transaction 注解失效的场景,希望大家以后能够避免踩坑:

  1. @Transactional 应用在非 public 修饰的方法上
  2. @Transactional 注解属性 propagation 设置问题
  3. @Transactional 注解属性 rollbackFor、noRollbackFor 设置问题
  4. 同一个类中方法调用,导致 @Transactional 失效
  5. 异常被 catch 导致 @Transactional 失效

总结

本文重点阐述了 @Transaction 注解的属性使用,帮助大家快速了解。希望能够有所帮助!!!

  • 45
    点赞
  • 155
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值