spring中,当同一个类中两个方法互相调用时,@Transactional注解失效问题原理理解

问题详述

具体情况如下:

  1. 我们使用spring容器进行bean管理时;
  2. 我们使用spring进行事务管理也就是使用@Transactional;
  3. 我们在同一个业务类中,不同的两个方法上都使用了@Transactional注解,一个记为方法A,另一个记为方法B;
  4. 该业务类中的方法A调用了方法B,且B中我们使用传播级别为无论如何都创建一个新的事务执行,且异常处理后不影响外层,也就是Propagation.NESTED;
  5. 结果发现被调用的方法B中的事务失效了,也就是部分成功提交,部分未成功执行;

解决办法

网上可以查到很多种,但一般我都用比较简单的一种:就是在该类中自动注入本类bean,使用@Autowired即可,然后使用这个注入的bean去调用本类方法,即可达到两方法事务都起效

疑问

  1. 查过上述解决办法的各种理解,感觉很迷;主要是说,直接调用同类方法使用的是this.xxx()的方式;这个说法没有任何问题。
  2. 问题是:自动注入的spring容器中的该类对象本来就是加强过的代理对象,那么this此时指代的不应该就是这个代理对象吗,那么调用到的为什么不是增强过的对象的方法呢?
  3. 或者说,代理对象其实是在每次调用时才产生的?实际存在于容器中的还是原始对象?

学习和理解

针对问题3:看了spring书中的aop方面的介绍,代理对象生成是bean后处理器处理的,那么很明显,就是在容器初始化的时候生成的代理对象了(前提:我们使用的是ApplicationContext的这个子容器,而不是BeanFactory这个最原始的容器,一般都是用的前者);因为bean后处理器的处理时机是紧跟着bean的初始化结束后的。也就是说,容器中存储的就已经是增强结束的代理对象了,而不是原始对象!

针对问题2:从动态代理的原理出发可以发现问题:

  1. 其实代理对象维护着一个原始对象的引用,在执行代理对象的增强方法时,只是在使用原始对象调用原始方法的前后,去执行了一些增强操作。也就是说,实际上,还是要调用原始对象的原始方法,而且使用的就是原始对象。
  2. 那也就清晰了,因为在调用增强方法时,也就是增强方法A时;先执行了执行前的增强,再用原始对象去调用方法A的;然后在方法A中调用方法B,所以这里的this指向的就是原始对象;而非增强对象!!!那么一切就能够合理解释了。

后记

有写得不对的地方欢迎探讨。。。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐