面试官——你知道哪几种事务失效的场景?

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

转载声明:转载请注明出处,本技术博客是本人原创文章

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 面试官——你知道哪几种事务失效的场景?

前言

  • 声明式事务是Spring功能中最爽之一,可是有些时候,我们在使用声明式事务并未生效,这是为什么呢?- 今天陈某带大家来聊一聊声明事务的几种失效场景。本文将会从以下两个方面来说一下事务为什么会失效?1. @Transactional介绍1. @Transactional失效场景
    这是我历时三个月总结的 Java 面试 + Java 后端技术学习指南,本人这几年及春招的总结,目前,已经拿到了大厂offer,拿去不谢!(目录部分截图)

下载方式

1. 首先扫描下方二维码

2. 后台回复「Java面试」即可获取

@Transactional介绍

  • @Transactional是声明式事务的注解,可以被标记在 类上 接口 方法上。- 该注解中有很多值得深入了解的几种属性,我们来看一下。

    transactionManager

  • 指定事务管理器,值为 bean的名称,这个主要用于多事务管理器情况下指定。比如多数据源配置的情况下。

    isolation

  • 事务的隔离级别,默认是 Isolation.DEFAULT。- 几种值的含义如下:-
    • Isolation.DEFAULT:事务默认的隔离级别,使用数据库默认的隔离级别。- Isolation.READ_UNCOMMITTED:这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。- Isolation.READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻读。- Isolation.REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。- Isolation.SERIALIZABLE:这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。

      propagation

    • 代表事务的传播行为,默认值为 Propagation.REQUIRED。- Propagation.REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。比如A方法内部调用了B方法,此时B方法将会使用A方法的事务。- Propagation.MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。- Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。- Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。- Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。比如A方法使用默认的事务传播属性,B方法使用 REQUIRES_NEW,此时A方法在内部调用B方法,一旦A方法出现异常,A方法中的事务回滚了,但是B方法并没有回滚,因为A和B方法使用的不是同一个事务,B方法新建了一个事务。- Propagation.NESTED:支持当前事务,新增 Savepoint点,也就是在进入子事务之前,父事务建立一个回滚点,与当前事务同步提交或回滚。子事务是父事务的一部分,在父事务还未提交时,子事务一定没有提交。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

      timeout

    • 事务的超时时间,单位为秒。

      readOnly

    • 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。如果一个事务只涉及到只读,可以设置为true。

      rollbackFor 属性

    • 用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。- 默认是在 RuntimeException Error上回滚。

      noRollbackFor

    • 抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。

      @Transactional失效场景

    • 声明式事务失效的场景有很多,陈某这里只是罗列一下几种常见的场景。

      底层数据库引擎不支持事务

    • 如果数据库引擎不支持事务,则Spring自然无法支持事务。

      在非public修饰的方法使用

    • @Transactional注解使用的是AOP,在使用动态代理的时候只能针对 public方法进行代理,源码依据在 AbstractFallbackTransactionAttributeSource类中的 computeTransactionAttribute方法中,如下:
      ```
      protected TransactionAttribute computeTransactionAttribute(Method method,
          Class<?> targetClass) {
              // Don’t allow no-public methods as required.
              if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
              return null;
      }
    
    - 此处如果不是标注在`public`修饰的方法上并不会抛出异常,但是会导致事务失效。
    ### 异常被 " 踹死了 "
    - 这种情况小白是最容易犯错的,在整个事务的方法中使用`try-catch`,导致异常无法抛出,自然会导致事务失效。伪代码如下:
    

    @Transactional
    public void method(){
      try{
        //插入一条数据
        //更改一条数据
      }catch(Exception ex){
        return;
      }
    }

    
    
    ### 方法中调用同类的方法
    - 简单的说就是一个类中的`A方法`(未标注声明式事务)在内部调用了`B方法`(标注了声明式事务),这样会导致B方法中的事务失效。- 代码如下:
    

    public class Test{
      public void A(){
        //插入一条数据
        //调用B方法
        B();
      }
      
      @Transactional
      public void B(){
        //插入数据
      }
    }

    ```

    • 为什么会失效呢?:其实原因很简单,Spring在扫描Bean的时候会自动为标注了 @Transactional注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作,但是同类中的方法互相调用,相当于 this.B(),此时的B方法并非是代理类调用,而是直接通过原有的Bean直接调用,所以注解会失效。- 如何解决呢?:这就涉及到注解失效的原因了,后续文章会介绍到,这里不过多介绍了。

      rollbackFor属性设置错误

    • 很容易理解,指定异常触发回滚,一旦设置错误,导致一些异常不能触发回滚,此时的声明式事务不就失效了吗。

      noRollbackFor属性设置错误

    • 这个和rollbackFor属性设置错误类似,一旦设置错误,也会导致异常不能触发回滚,此时的声明式事务会失效。

      propagation属性设置错误

    • 事务的传播属性在上面已经介绍了,默认的事务传播属性是 Propagation.REQUIRED,但是一旦配置了错误的传播属性,也是会导致事务失效,如下三种配置将会导致事务失效:-
      • Propagation.SUPPORTS- Propagation.NOT_SUPPORTED- Propagation.NEVER

        原始SSM项目,重复扫描导致事务失效

      • 在原始的SSM项目中都配置了 context:component-scan并且同时扫描了service层,此时事务将会失效。- 按照Spring配置文件的加载顺序来说,会先加载Springmvc的配置文件,如果在加载Springmvc配置文件的时候把service也加载了,但是此时事务还没加载,将会导致事务无法成功生效。- 解决方法很简单,把扫描service层的配置设置在Spring配置文件或者其他配置文件中即可。

        总结

      • 事务失效的原因很多,但是千万不要做到一知半解,只有深入理解了,才能在面试过程中对答如流。- 今天的文章就到此结束了,如果觉得陈某写得不错,有所收获的,关注在看来一波,你们的鼓励,将会是我写作的动力,谢谢支持!!!
        最后,再附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,这是本人这几年及春招的总结,目前,已经拿到了大厂offer,拿去不谢!(目录部分截图)

      下载方式

      1. 首先扫描下方二维码

      2. 后台回复「Java面试」即可获取

      原文地址:https://sihai.blog.csdn.net/article/details/109465485

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

转载声明:转载请注明出处,本技术博客是本人原创文章

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 面试官——你知道哪几种事务失效的场景?


 上一篇
为什么程序员都不喜欢使用switch,而是大量的 if……else if ? 为什么程序员都不喜欢使用switch,而是大量的 if……else if ?
  点击上方 **好好学java **,选择 **星标 **公众号 重磅资讯、干货,第一时间送达 今日推荐:微信支付的软件架构,牛逼!个人原创+1博客:点击前往,查看更多 出处:熊爸爸的科技工坊 链接:3g.163.com/tech/
2021-04-04
下一篇 
如何设计一个安全的对外接口 如何设计一个安全的对外接口
  点击上方 **好好学java **,选择 **星标 **公众号 重磅资讯、干货,第一时间送达 今日推荐:为什么程序员都不喜欢使用switch,而是大量的 if……else if ?个人原创+1博客:点击前往,查看更多 作者:ksfz
2021-04-04