Spring事务在同类中调用失效的根本原因是未经过代理对象,导致TransactionInterceptor未执行;必须为public方法;推荐拆分到不同Bean中,或通过AopContext、@Lazy注入自身、ApplicationContext等方式绕过this调用。

Spring 事务在同一个类内部调用失效,根本原因是:调用没有经过代理对象,事务拦截器(TransactionInterceptor)压根没执行。外部调用时走的是 Spring 生成的代理(JDK 或 CGLIB),而 this.methodB() 是直接对原始对象调用,绕过了整个 AOP 链。
必须是 public 方法
事务方法本身必须声明为 public。private、protected 或包级访问的方法,Spring 无法通过代理增强,事务注解会被忽略(Spring 5.0+ 会直接报错)。
拆分到不同 Bean 中(推荐)
最清晰、最符合单一职责和可测性的做法:把带 @Transactional 的方法移到另一个独立的 Service 类中,再通过 @Autowired 注入调用。
- 避免自调用问题,天然走代理
- 逻辑边界明确,便于单元测试和复用
- 团队协作和代码审查更友好
通过 AopContext 获取当前代理对象
在调用方类上添加 @EnableAspectJAutoProxy(exposeProxy = true),然后在方法内用:
立即学习“Java免费学习笔记(深入)”;
((YourService) AopContext.currentProxy()).transactionalMethod();
注意:仅限当前类内部调用,且需确保开启 exposeProxy,否则会抛 IllegalStateException。
注入自身 Bean(慎用)
在本类中 @Autowired @Lazy private YourService self;,再调用 self.transactionalMethod()。
- 依赖循环风险低(因
@Lazy延迟加载) - 但语义略怪:自己注入自己,可读性打折扣
- 不适用于构造器注入场景
用 ApplicationContext 获取 Bean
注入 ApplicationContext,然后调用:
applicationContext.getBean(YourService.class).transactionalMethod();
本质和注入自身 Bean 类似,只是获取方式不同;同样绕过 this 直接调用,走代理链。


















