@Transcation详解

前言

本文主要详细介绍@Transcation注解,包括@Transcation的注解属性,源码等知识,如果你想了解SpringBoot中如何使用事务,请阅读文章:一文读懂SpringBoot事务管理

@Transcation注解属性

下面是@Transcation源码:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    //当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。
    @AliasFor("transactionManager")
    String value() default "";

    //当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。
    //如 @Transactional(value = "jpaTransactionManager")
    @AliasFor("value")
    String transactionManager() default "";
    
    //事务的传播行为
    //默认如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务
    Propagation propagation() default Propagation.REQUIRED;

    //事务的隔离级
    //默认使用底层数据库自己的隔离级别
    Isolation isolation() default Isolation.DEFAULT;

    //事务超时时间,如果超过该时间限制但事务还没有完成,则自动回滚事务
    //-1表示永不超时
    int timeout() default -1;

    //事务是否为只读事务,为了忽略那些不需要事务的方法,如读取数据,可以设置 read-only 为 true。
    boolean readOnly() default false;

    //用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
    Class<? extends Throwable>[] rollbackFor() default {};

    //用于指定能够触发事务回滚的异常名称,可以指定多个
    String[] rollbackForClassName() default {};

    //抛出指定的异常类型,不回滚事务,可以指定多个
    Class<? extends Throwable>[] noRollbackFor() default {};

    //抛出指定的异常名称,不回滚事务,可以指定多个。
    String[] noRollbackForClassName() default {};
}

propagation(传播)

propagation事务传播行为,它是一个枚举,可选值如下:

  • **REQUIRED(默认值):**如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。
  • **SUPPORTS:**如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务方式继续运行。
  • **MANDATORY:**如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
  • **REQUIRES_NEW:**重新创建一个新的事务,如果当前存在事务,暂停当前的事务。
  • **NOT_SUPPORTED:**以非事务的方式运行,如果当前存在事务,暂停当前的事务。
  • **NEVER:**以非事务的方式运行,如果当前存在事务,则抛出异常。
  • **NESTED:**和 REQUIRED 效果一样。

isolation(隔离)

isolation(隔离)事务隔离级别,它是一个枚举,可选择如下:

  • **DEFAULT(默认值):**使用底层数据库默认的隔离级别。
  • **READ_UNCOMMITTED:**未提交读。在并发情况下,数据库可能会产生并发问题,如脏读,不可重复读,幻影读。
  • **READ_COMMITTED:**可提交读。可以防止脏读,但在并发问题下可能会导致不可重复读,幻影读。
  • **REPEATABLE_READ:**可重复读。可以防止脏读、可重复读。mysql 默认隔离级别。
  • **SERIALIZABLE:**串行事务。最高事务隔离级别,可以防止脏读、可重复读、幻读。

关于事务的隔离级别,在此就不过多介绍,读者可以自行了解。

rollbackFor(回滚)

rollbackFor指定程序运行时回滚的异常,默认配置下Spring只会回滚运行时异常(继承自RuntimeException的异常)或Error,编译时异常默认不会回滚。

如果异常为:throw new RuntimeException("xxx"); 则事务会回滚
如果异常为:throw new Exception("xxx"); 则事务会不回滚

如果你想在方法中指定回滚的异常,则可以通过 rollbackFor属性指定,如 :@Transactional(rollbackFor=Exception.class)、@Transactional(rollbackFor=SQLException.class) 等
如果 @Transactional 标注的方法中使用 try{}catch{}捕获处理了异常,则事务不再回滚,如果想让事务回滚,则必须继续往外抛:

try{
    xxx
}catch(Exception e)throw new RuntimeException("xxx",e)

noRollbackFor

noRollbackFor如果程序运行时碰到某些异常不进行事务回滚,可以使用noRollbackFor属性进行指定,比如:@Transactional(notRollbackFor=RunTimeException.class),程序运行时碰到RunTimeException事务将不会回滚。

@Transactional事务实现机制

  1. @Transactional 声明目标方法后,Spring Framework 默认使用 AOP 代理,代码运行时生成一个代理对象,根据 @Transactional 的属性配置,代理对象决定该声明 @Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截。
  2. 在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器 AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
  3. Spring AOP 代理有 CglibAopProxy 和 JdkDynamicAopProxy 两种,以 CglibAopProxy 为例,对于 CglibAopProxy,需要调用其内部类的 DynamicAdvisedInterceptor 的 intercept 方法。对于 JdkDynamicAopProxy,需要调用其 invoke 方法。
  4. 默认的代理模式下,只有目标方法由外部调用,才能被 Spring 事务拦截器拦截。在同一个类中的两个方法直接调用,是不会被 Spring 的事务拦截器拦截。

@Transactional事务失效场景

失效场景描述
@Transactional 应用在非 public 修饰的方法上只能标记在 public 修饰的方法上
@Transactional 注解传播属性 propagation 设置错误类与类相互调用时,被调用者可以新开事务,不走事务。
@Transactional 注解回滚异常属性 rollbackFor 设置错误默认配置下 Spring 只会回滚运行时异常(非受检查异常),即继承自 RuntimeException 的异常或者 Error。
异常被 catch 捕获,没有继续往外抛,导致 @Transactional 失效使用 try{}catch{}捕获处理了异常,事务的AOP无法捕获异常,导致即使出现了异常,事务也不会回滚。如果想让事务回滚,则必须继续往外抛。
数据库存储引擎不支持事务导致失效Spring Data JPA 默认使用 MyISAM 作为 Mysql 的存储引擎,此引擎不支持事务、不支持外键。InnoDB 存储引擎支持事务,可以在配置文件中进行指定。
抛出的异常不正确@Transactional 默认只回滚 RuntimeException(运行时异常)和 Error(错误)。
多线程影响1、子线程中调用其它类中的方法,而目标方法中有事务注解时,则目标方法受事务控制,但与主线程事务不是同一个。
2、子线程中直接调用本类中的方法,即使目标方法有事务注解,目标方法也不受事务控制。
3、主线程、子线程因为获取到的数据库连接不一样,从而是两个不同的事务。
同类中内部方法相互调用,默认代理模式下,如果调用者自己已经有事务,则被调用的永远和它处于同一事务。被调用者的设置的 REQUIRES_NEW、NOT_SUPPORTED、NEVER 等等都不会有效
同类中调用者方法上面未加 @Transactionl ,被调用方法上面加 @Transaction 此时事务不会开启,不会生效。

参考资料:
Spring Boot @Transactional 配置事务管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值