• 事务特性、事务隔离级别、spring事务传播特性


    事务分为编程式事务 与 声明式事务 这里描述常用的声明式事务的原理。

    @Transactional 实现机制:

      当在方法上使用@Transactional 时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常决定提交或回滚事务。


    @Transactional 中相关参数说

    name        :当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。

    propagation   :事务的传播行为,默认值为 REQUIRED。

    isolation      :事务的隔离度,默认值采用 DEFAULT。

    timeout             :事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。

    read-only    :指定事务是否为只读事务,默认false 为了忽略那些不需要事务的方法,如读取数据可以设置read-only为true。

    rollback-for      :用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。

    no-rollback- for:抛出 no-rollback-for 指定的异常类型,不回滚事务。

    (重点说明)propagation : 事务的传播行为 

    Propagation.REQUIRED(默认):如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。

    Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

    Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

    Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。

    Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。

    Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。

    Propagation.NESTED: Propagation.REQUIRED 效果一样。

    /*
    *测试用例:
    */1:默认事务 (propagation.REQUIRED)
    class B{
      @Transactional
      public void funB(){ }
    }
    cladd A {
      @Transactional
       public void funA(){ new B().funB(); }
    }
    
    //结果为:当B失败,则funA/B同时回滚
     
    //例2:(Propagation.REQUIRES_NEW) 创建新事物
    //需求:funA如果抛异常不得影响funB的执行,使用新启事务 Propagation.REQUIRES_NEW
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void funA(){ funB} //直接失效
    //这里有个坑!funB必须写在另一个类中才生效! 在默认的代理模式下,只有目标方法由外部调用,才能被 Spring 的事务拦截器拦截。
    //在同一个类中的两个方法直接调用,是不会被 Spring 的事务拦截器拦截,可以使用 AspectJ 取代 Spring AOP 代理来解决这个问题。
     
    //例3:(Propagation.MANDATORY) 事务有则加入无则报错
    class B{
      @Transactional(propagation = Propagation.MANDATORY)
      public void funB(){ }
    }
    cladd A {
      public void funA(){ new B().funB(); }
    }
    
    //结果:将报错因为在调用funB的时候不存在事务。
     
    //例4:(Propagation.SUPPORTS)事务有则加入,无则按非事务运行。  与例三相对
    class B{
      @Transactional(propagation = Propagation.SUPPORTS)
      public void funB(){ }
    }
    cladd A {
      public void funA(){ new B().funB(); }
    }
    
    //例5:Propagation.NOT_SUPPORTED 与 Propagation.NEVER 都是以非事务方式执行,
    //后者更狠只要有事务就报错,而前者只是暂停。

    不会执行事务的场景:懂原理才能知道为什么不执行!!

    为什么不启用事务的排查逻辑:

    1、public:SpringAOP中涉及的核心类CglibAopProxy 或者 JdkDynamicAopProxy 无法获取@Transactional 的相关配置,底层使用反射读取配置信息,但该方法非Public 所以获取不到。

    2、try/catch:核心类找到了你@Transactional 的配置,但你在方法里catch 掉了,所以事务拦截器拦截的时候抓不到异常导致无法回滚

    3、同类中自调用:找到了,也没有catch.但还是没有回滚,看看是不是在同一个类中形成了自调用(同类中方法事务A调用事务方法B)这里可以参考IBM的这个博客

    4、propagation:找到没也没catch也无自调用,检查Propagation 参数是否配置了不启用事务的参数

    5、回滚异常检测:检查rollbackFor 以及 noRollbackFor 这里检查的异常是否有问题。

     


     

    参考文章:

    https://blog.csdn.net/nextyu/article/details/78669997  《Spring Boot 中使用 @Transactional 注解配置事务管理》

    https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html 《透彻的掌握 Spring 中@transactional 的使用》

    https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations

    《Spring框架参考文档》

  • 相关阅读:
    模型命名规范
    Jquery 将表单序列化为Json对象
    Failed to read auto-increment value from storage engine错误的处理方法
    css样式表中设置table的第一列的宽度是固定值
    thinkphp中I("parm")用法的注意事项
    获取凌晨00:00:00的时间
    php empty()和isset()的区别
    react续集
    react的笔记整理
    vuex
  • 原文地址:https://www.cnblogs.com/lanSeGeDiao/p/10919415.html
Copyright © 2020-2023  润新知