码迷,mamicode.com
首页 > 其他好文 > 详细

处理事务回滚

时间:2020-06-30 17:43:10      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:nas   void   无法   src   framework   tran   防止   需要   action   

处理事务回滚

参考文献:《极客时间-Java业务开发常见错误100例》https://time.geekbang.org/column/article/213295

大多数Spring Boot项目只需要在方法上标记@Transactional注解,即可一键开启方法的事务性配置。

保证事务生效

  1. 务必确认调用 @Transactional 注解标记的方法是 public 的

    除非特殊配置(比如使用 AspectJ 静态织入实现 AOP),否则只有定义在 public 方法上的 @Transactional 才能生效。原因是,Spring 默认通过动态代理的方式实现 AOP,对目标方法进行增强,private 方法无法代理到,Spring 自然也无法动态增强事务处理逻辑。
    
    如果要针对 private 方法启用事务,动态代理方式的 AOP 不可行,需要使用静态织入方式的 AOP,也就是在编译期间织入事务增强代码,可以配置 Spring 框架使用 AspectJ 来实现 AOP。你能否参阅 Spring 的文档“Using @Transactional with AspectJ”试试呢?注意:AspectJ 配合 lombok 使用,还可能会踩一些坑。 https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-aspectj 
    
  2. 通过 Spring 注入的 Bean 进行调用的。使用 try…catch…来包裹标记了 @Transactional 注解的方法,必须通过代理过的类从外部调用目标方法才能生效。

    Spring 通过 AOP 技术对方法进行增强,要调用增强过的方法必然是调用代理后的对象。
    - CGLIB 通过继承方式实现代理类,private 方法在子类不可见,自然也就无法进行事务增强;
    - this 指针代表对象自己,Spring 不可能注入 this,所以通过 this 访问方法必然不是代理。
    
    正确使用:在 Service 内部注入自己调用自己的 方法() 可以正确实现事务,但更合理的实现方式是,让 Controller 直接调用之前定义的 Service 的 方法() ,因为注入自己调用自己很奇怪,也不符合分层实现的规范
    

技术图片

保证回滚

默认情况下,出现 RuntimeException(非受检异常)或 Error 的时候,Spring 才会回滚事务。

修复方式:

  1. 自己捕捉,手动设置让当前事务处于回滚状态

    @Transactionalpublic void createUserRight1(String name) {
        try {
            userRepository.save(new UserEntity(name));
            throw new RuntimeException("error");
        } catch (Exception ex) {
            log.error("create user failed", ex); 
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
    
  2. 在注解中声明rollbackFor ,期望遇到所有的 Exception 都回滚事务(来突破默认不回滚受检异常的限制)

    @Transactional(rollbackFor = Exception.class)
    

子方法回滚,主方法不回滚

虽然捕获了子方法的异常,但是因为没有开启新事务,而当前事务因为异常已经被标记为rollback了,所以最终还是会回滚。

解决方法:想办法让子逻辑在独立事务中运行

  • 为注解加上 propagation = Propagation.REQUIRES_NEW 来设置 REQUIRES_NEW 方式的事务传播策略,也就是执行到这个方法时需要开启新的事务,并挂起当前事务。

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    

    主方法没什么变化,同样需要try catch捕获异常,防止异常漏出去导致主事务回滚

处理事务回滚

标签:nas   void   无法   src   framework   tran   防止   需要   action   

原文地址:https://www.cnblogs.com/shinl00/p/13214551.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!