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

Spring @Transactional事务未回滚问题求助(CrudRepository场景)

事务回滚失效问题排查与解决

问题描述

我给业务方法添加了@Transactional注解,当方法进入catch分支捕获异常后抛出自定义异常,或是主动抛出RuntimeException时,期望此前通过CrudRepository保存到数据库的数据能触发回滚,但实际数据仍留存,即使设置rollbackFor=Exception.class也无法生效,请问如何实现正确的事务回滚?

代码示例

示例1:捕获异常后抛出自定义异常

@Transactional
public RpaLog createRpaLogObject(CreateRpaLogObjectRequest request) {
    RpaLog rpaLog = new RpaLog();
    try {
        rpaLog.setFunctionName(request.getFunctionName());
        rpaLog.setStatus(request.getStatus());
        rpaLog.setCreatedDate(HelperUtils.getCurrentTimestamp());
        rpaLog = rpaLogRepository.save(rpaLog);

        String externalApiUrl = rpaConfig.getEndpoint() + rpaLog.getId();
        restTemplate.getForObject(
                externalApiUrl,
                ExternalApiResponse.class
        );
    }catch (Exception e){
        throw new CreationFailedException(MessageConstants.RPA_CREATION_FAILED + request.getFunctionName());
    }

    return rpaLog;
}

示例2:主动抛出RuntimeException

@Transactional(rollbackFor = Exception.class)
public RpaLog createRpaLogObject(CreateRpaLogObjectRequest request) {
    RpaLog rpaLog = new RpaLog();
    rpaLog.setFunctionName(request.getFunctionName());
    rpaLog.setStatus(request.getStatus());
    rpaLog.setCreatedDate(HelperUtils.getCurrentTimestamp());
    rpaLog = rpaLogRepository.save(rpaLog);

    throw new RuntimeException("Throw example");
}

常见失效原因及解决办法

1. 事务注解未被Spring识别

  • 原因:业务类未被Spring容器管理,或者不在Spring组件扫描范围内。
  • 解决:给业务类添加@Service/@Component注解,确保Spring的@ComponentScan路径覆盖该类所在包。

2. 自定义异常类型不符合回滚规则

  • 原因:如果CreationFailedException是受检异常(继承自Exception而非RuntimeException),默认@Transactional只会对运行时异常(RuntimeException)和错误(Error)触发回滚,显式设置rollbackFor=Exception.class才会生效,但要确保注解配置正确。
  • 解决:
    • 要么让CreationFailedException继承RuntimeException,无需额外配置即可触发回滚;
    • 要么在@Transactional中显式指定回滚的异常类型:@Transactional(rollbackFor = {CreationFailedException.class, Exception.class})。

3. 数据库引擎不支持事务

  • 原因:比如MySQL使用了MyISAM引擎,该引擎不支持事务;PostgreSQL等数据库如果未正确配置事务隔离级别也可能有问题。
  • 解决:将MySQL表引擎修改为InnoDB,确保数据库本身支持事务操作。

4. 方法内部调用导致AOP代理失效

  • 原因:如果是同一个类内部调用带@Transactional注解的方法,Spring的AOP代理不会生效,事务逻辑不会被触发。
  • 解决:
    • 将事务方法抽取到单独的Bean中,通过依赖注入调用;
    • 或者在当前类中注入自身的代理实例(如通过@Autowired注入当前类,而非直接this.方法名()调用)。

5. 事务管理器配置错误

  • 原因:Spring未正确配置事务管理器,或者事务管理器关联的数据源不正确。
  • 解决:检查配置类中是否正确定义了DataSourceTransactionManager,并关联了业务使用的数据源:
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

修正后的代码示例

示例1修正版

@Service
public class RpaLogService {
    @Autowired
    private RpaLogRepository rpaLogRepository;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RpaConfig rpaConfig;

    // 显式指定需要回滚的异常类型
    @Transactional(rollbackFor = {CreationFailedException.class, Exception.class})
    public RpaLog createRpaLogObject(CreateRpaLogObjectRequest request) {
        RpaLog rpaLog = new RpaLog();
        try {
            rpaLog.setFunctionName(request.getFunctionName());
            rpaLog.setStatus(request.getStatus());
            rpaLog.setCreatedDate(HelperUtils.getCurrentTimestamp());
            rpaLog = rpaLogRepository.save(rpaLog);

            String externalApiUrl = rpaConfig.getEndpoint() + rpaLog.getId();
            restTemplate.getForObject(externalApiUrl, ExternalApiResponse.class);
        } catch (Exception e) {
            throw new CreationFailedException(MessageConstants.RPA_CREATION_FAILED + request.getFunctionName());
        }
        return rpaLog;
    }
}

示例2修正版

@Service
public class RpaLogService {
    @Autowired
    private RpaLogRepository rpaLogRepository;

    @Transactional(rollbackFor = Exception.class)
    public RpaLog createRpaLogObject(CreateRpaLogObjectRequest request) {
        RpaLog rpaLog = new RpaLog();
        rpaLog.setFunctionName(request.getFunctionName());
        rpaLog.setStatus(request.getStatus());
        rpaLog.setCreatedDate(HelperUtils.getCurrentTimestamp());
        rpaLog = rpaLogRepository.save(rpaLog);

        throw new RuntimeException("Throw example");
    }
}

内容的提问来源于stack exchange,提问作者Riki Ahmad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:13:16