Spring事务-随笔

测试项目github链接

  1. @Transactional 由于serviceImp实现的service,所以AOP默认用的Spring AOP中的jdk动态代理。因此private、protected、包级、static的不能生效,但是不报错。另外由于AOP,同类下的其他方法上的@Transactional不生效,因为是类内部方法调用,动态代理不生效。解决方法:

    1. 写在不同的类里;
    // eg:
    @Service("studentService")
    public class StudentServiceImpl implements StudentService {
      
      @Resource
      private TeacherService teacherService;
      
      @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
      @Override
      public void A(Integer id) throws Exception {
        this.insert(id);
        teacherService.insert(id);
      }
    }
    
    1. 同类,但是用AspectJ获取代理对象,用代理对象再调用同类的B方法;
    // eg:
    @Service("studentService")
    public class StudentServiceImpl implements StudentService {
      
      @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
      @Override
      public void A(Integer id) throws Exception {
        this.insert(id);
        ((StudentServiceImpl)AopContext.currentProxy()).B(id);
      }
    }
    
    1. 同类,依赖注入自己,再调用注入的对象的方法
    // eg:
    @Service("studentService")
    public class StudentServiceImpl implements StudentService {
    
      @Resource
      private StudentService studentService;
    
      @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
      @Override
      public void A(Integer id) throws Exception {
        this.insert(id);
        studentService.insert(id);
      }
    }
    

(ps: 可以在 org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 中打断点查看一些事务调用情况)

  1. @Transactional指定的spring事务传播对 TransactionTemplate transactionTemplate 同样有效。

    • TransactionTemplate transactionTemplate可以通过transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER);设置事务传播级别。
    • 注意,如果在@Transactional方法内又使用transactionTemplate,那可能导致最后开了两个事务(具体看transactionTemplate设置的事务传播级别是什么,如果@Transactional和transactionTemplate都是用REQUIRES_NEW,那就是两个不相干的事务了)
  2. REQUIRES_NEW 和 NESTED的区别,前者开启和原事务完全无关的新事务,回滚是独立的新事务被回滚;后者如果已经存在事务,则仅设置savepoint,和原事务是同一个事务,不过就是后者回滚只回滚到自己的检查点。如果原本没有事务,那么NESTED就和REQUIRES一样都是新建事务。

  3. 由于@Transactional这边Spring传播级别通过AOP实现,所以调用方法的时候就确认是否有父事务环境了,不会等运行到中间调用B之后又重新判断(所以如果外层是Propagation.NEVER,即时方法内临时调用另一个事务方法,也不会抛出异常,外部方法始终无事务,内部被调用方法是独立的一个事务)。

  4. 同一个类中方法调用会可能导致@Transactional失效,重新使得@Transcational生效的方法:

    1. pom.xml 中添加AspectJ:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
    1. 启动类上添加 @EnableAspectJAutoProxy(exposeProxy = true)
    2. AopContext.currentProxy()操作当前的代理类
    AopContext.currentProxy().A; // 调用代理类的.A方法。
    
  5. TransactionTemplate相关

    • transactionTemplate.execute本身就是开一个事务,也可以手动设定事务传播级别等。和@Transactional注解的区别就是注解的形式在方法执行前设置事务传播级别和开启事务,而transactionTemplate只在execute的时候才开启事务。
    • TransactionTemplate transactionTemplate可以通过transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_NEVER);设置事务传播级别
  6. Spring AOP知识回顾

    1. 对于基于接口动态代理的AOP事务增强来说,由于接口的方法是public的,这就要求实现类的实现方法必须是public的, 不能是protected,private等,同时不能使用static的修饰符。

      所以,可以实施接口动态代理的方法只能是使用“public” 或 “public final”修饰符的方法,其它方法不可能被动态代理,相应的也就不能实施AOP增强,也即不能进行Spring事务增强。

    2. 基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建子类的方式进行AOP增强植入的。由于使用final、static、private修饰符的方法都不能被子类覆盖,相应的,这些方法将不能被实施的AOP增强。

    ps:如果我们自己用jdk动态代理的原始写法,其实可以setAccessible(true)访问private修饰的东西

spring事务传播级别
Spring五个事务隔离级别和七个事务传播行为
transactionTemplate用法
Spring中Transactional放在类级别和方法级别上有什么不同?
Spring @Transactional属性可以在私有方法上工作吗?
Aspectj与Spring AOP比较
JDK动态代理
Spring : REQUIRED和NESTED的区别
不同类的方法 事务问题_Spring 事务原理和使用,看完这一篇就足够了
Spring中同一类@Transactional修饰方法相互调用的坑
@Transactional同类方法调用不生效及解决方法
Spring中事务的Propagation(传播性)的取值
spring+mybatis 手动开启和提交事务
AopContext.currentProxy()

(Ashiamd的github个人学习笔记)[https://ashiamd.github.io/docsify-notes/#/README] ~小尾巴~
原文地址:https://www.cnblogs.com/Ashiamd/p/15085827.html