You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何同一类中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:33:31