为何同一类中methodC的@Transactional注解未生效?
Spring @Transactional 内部调用不生效问题解决
问题根源
Spring的@Transactional是基于动态代理实现的:只有当方法调用经过Spring生成的代理对象时,事务逻辑才会被触发。而你当前的代码里,methodB直接调用同一个类中的methodC,属于内部方法调用,不会经过代理类,所以methodC上的@Transactional注解完全不起作用。
解决方案
1. 将事务方法抽至独立Service类
把methodC的逻辑迁移到一个新的Service类中,通过依赖注入调用该类的方法,确保调用走代理链路。
示例代码:
// 新建事务专用Service @Service public class TxService { @Autowired private Service1 service1; @Autowired private Service2 service2; @Transactional(rollbackFor = Exception.class) public void methodC() throws MyException, Exception { service1.someDeleteAndInserts(); service2.someDeleteAndInserts(); } } // 修改原MyService @Service public class MyService { @Autowired private TxService txService; @Override public void methodA() { methodB(); } private void methodB() { try { txService.methodC(); // 调用外部Service方法,触发事务 } catch (MyException | Exception e) { System.out.println(e); } } }
2. 通过AopContext获取代理对象调用
开启Spring暴露代理对象的配置,在内部调用时通过代理对象触发事务逻辑。
步骤1:开启暴露代理
@Configuration @EnableAspectJAutoProxy(exposeProxy = true) public class AppConfig { // 其他配置 }
步骤2:修改内部调用逻辑
@Service public class MyService { // ... 注入依赖不变 private void methodB() { try { // 通过代理对象调用methodC,触发事务 ((MyService) AopContext.currentProxy()).methodC(); } catch (MyException | Exception e) { System.out.println(e); } } @Transactional(rollbackFor = Exception.class) public void methodC() throws MyException, Exception { service1.someDeleteAndInserts(); service2.someDeleteAndInserts(); } }
注意:这种方式耦合了Spring AOP API,仅适合临时调整,不推荐在核心业务代码中大量使用。
3. 在调用链入口添加事务注解
如果业务允许,直接在调用链的入口方法(如methodA)或中间公共方法上添加@Transactional,让整个调用链路处于同一个事务中。
示例:
@Service public class MyService { // ... 注入依赖不变 @Transactional(rollbackFor = Exception.class) @Override public void methodA() { methodB(); } private void methodB() { try { methodC(); } catch (MyException | Exception e) { System.out.println(e); } } public void methodC() throws MyException, Exception { service1.someDeleteAndInserts(); service2.someDeleteAndInserts(); } }
注意:private方法上的
@Transactional不会被Spring识别,若要给methodB加注解,需将其改为public。
额外注意事项
Spring事务默认仅在遇到RuntimeException或Error时回滚,如果你需要对checked异常(如自定义的MyException)触发回滚,必须在@Transactional中显式指定:
@Transactional(rollbackFor = Exception.class)
内容的提问来源于stack exchange,提问作者eunonek
相关产品推荐
相关产品推荐

