You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot 2.0事务无法回滚问题求助

解决Spring Boot 2.0.0中RuntimeException触发事务不回滚的问题

我之前也碰到过类似的Spring Boot版本升级后事务失效的情况,结合你的场景,咱们一步步排查和解决:

先排查最基础的事务生效前提

这些点在Spring Boot 1.5和2.0里逻辑一致,但升级时可能不小心改动了代码:

  • 方法可见性@Transactional注解只能作用在public方法上(默认JDK动态代理模式下),如果你的事务方法是private/protected或者默认访问权限,Spring代理根本不会拦截,自然不会触发回滚。
  • 避免自调用陷阱:如果是同一个类内部的方法调用(比如service.methodA()调用同一个service里的@Transactional方法methodB()),这种自调用会绕过Spring代理,事务不会生效。解决办法是通过ApplicationContext获取自身的代理对象来调用,或者把方法拆分到不同类中。
  • 异常是否被吞噬:检查你的事务方法内部有没有try-catch住RuntimeException但没重新抛出的情况:
    @Transactional
    public void updateData() {
        try {
            // 数据库操作
            throw new RuntimeException("触发回滚");
        } catch (RuntimeException e) {
            // 这里如果只打日志不抛出,事务感知不到异常,不会回滚
            log.error("操作失败", e);
            // 必须重新抛出:throw e;
        }
    }
    

针对Spring Boot 2.0的配置差异排查

Spring Boot 2.0在事务自动配置上有一些细微调整,结合你自定义的DatabaseConfiguration,重点检查这几点:

  1. 显式注册事务管理器
    Spring Boot 1.5中,当你启用@EnableJpaRepositories时,会自动注册JpaTransactionManager,但2.0的自动配置逻辑更严谨,如果你自定义了配置类,可能需要显式声明事务管理器:
    在你的DatabaseConfiguration中添加:

    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }
    

    这能确保Spring正确识别到事务管理器,避免自动配置和自定义配置冲突。

  2. 检查@EnableTransactionManagement的模式
    虽然默认是PROXY模式,但如果你的项目用到了AspectJ代理,需要显式指定:

    @EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
    

    不过大部分项目用默认的PROXY模式就够了,除非你有特殊的切面需求。

验证事务是否真的生效

开启事务相关的DEBUG日志,能帮你快速定位问题:
application.properties中添加:

logging.level.org.springframework.transaction=DEBUG
logging.level.org.springframework.orm.jpa=DEBUG

启动项目后,执行事务方法,查看日志:

  • 如果看到Creating new transaction with name [...],说明事务成功开启;
  • 如果抛出RuntimeException后看到Rolling back transaction for [...],说明回滚逻辑正常;
  • 如果根本看不到这些日志,说明事务代理没有生成,回到前面的基础排查点重新检查。

最后检查@Transactional的属性配置

虽然RuntimeException默认会触发回滚,但如果你的注解里有自定义配置,比如:

@Transactional(noRollbackFor = RuntimeException.class)
// 或者错误地指定了rollbackFor为非RuntimeException类型
@Transactional(rollbackFor = IOException.class)

这种情况会导致RuntimeException不触发回滚,确保你的注解没有这类错误配置。

内容的提问来源于stack exchange,提问作者Murilo Locatelli

火山引擎 最新活动