Spring Boot中this调用内部@Transactional方法仍共享同一事务的原因咨询
你这个问题其实戳中了Spring事务代理机制里一个容易混淆的点,我来一步步帮你拆解清楚:
核心结论先讲透
this.methodA()和this.methodB()确实绕过了Spring代理,它们自己的@Transactional注解完全没生效,但这两个方法是在methodD已经开启的事务上下文中执行的,所以复用了methodD的事务和数据库连接。
具体逻辑拆解
methodD的事务是正常开启的
当你通过Spring容器调用testTransactionalService.methodD()时,因为methodD标注了@Transactional,Spring的代理类会先开启事务,把当前线程和该事务的上下文(包括事务名称、绑定的数据库连接等)绑定,再执行methodD的业务逻辑。此时线程已经处于methodD的事务上下文环境中。内部this调用绕过代理,但不影响现有事务上下文
你在methodD里用this.methodA()、this.methodB()调用时,确实是直接调用了目标对象的原生方法,没有经过Spring代理,所以这两个方法上的@Transactional注解完全被忽略——它们并没有触发自己的事务创建逻辑。但这两个方法执行时,当前线程已经绑定了methodD的事务上下文,所以logTransactionInfo()拿到的都是methodD的事务信息,数据库连接也是同一个绑定好的连接。从你的日志就能佐证这一点
看你输出的日志内容:methodA
Is transaction active? true
Transaction name: org.o2.order.server.TestTransactionalService.methodD
...
methodB
Is transaction active? true
Transaction name: org.o2.order.server.TestTransactionalService.methodD所有方法的事务名称都是
methodD的,而非methodA或methodB自己的,这直接说明:methodA和methodB并没有触发自身的事务注解逻辑,只是复用了外层methodD的事务上下文。
你可以自己做个验证
如果把methodD上的@Transactional注解去掉,再运行testNoTransactionalD,你会发现所有方法的Is transaction active?都会输出false,而且每个方法的Connection hashCode大概率不一样——因为此时没有外层事务,内部this调用的@Transactional又不生效,所以每次getConnection()都是从数据源获取新连接,也没有事务绑定。
对比methodC的调用逻辑
methodC里用self().methodA()、self().methodB()调用时,是通过代理对象触发的调用,所以这两个方法的@Transactional会生效(默认传播行为REQUIRED会加入当前methodC的事务),最终同样复用同一个连接。这和methodD的情况本质不同:methodC是走代理触发了事务注解逻辑,methodD是直接调用方法复用外层事务上下文。
内容来源于stack exchange

