Spring抛出Exception时事务无法完全回滚问题求助
问题分析与解决方案
问题重现
@Transactional(rollbackFor = {Throwable.class, Exception.class}) public void notRollsBackCompletely() throws Exception { service1.modifyDb();// 执行成功 service2.modifyDb();// 抛出Exception }
现象:service1的数据库变更已回滚,但service2抛出异常前完成的更新/插入操作仍被提交。使用默认基于代理的Spring事务,所有服务方法及内部调用均无@Transactional注解。
核心原因
出现这种情况的核心是:service2.modifyDb()的数据库操作没有加入到当前方法的事务上下文,而是独立提交了。常见触发场景包括:
service2的DB操作使用了未被Spring事务管理的连接(比如手动创建Connection并执行commit);service2的数据源与service1不一致,且未被同一事务管理器接管;service2内部存在异步执行的DB逻辑,异步线程无法继承当前事务;- 全局事务配置中,给
service2的方法默认设置了REQUIRES_NEW这类强制开启新事务的传播特性。
解决步骤
- 检查DB操作方式:确保
service2.modifyDb()中所有数据库操作都通过Spring提供的模板类(如JdbcTemplate、MyBatis的SqlSession)执行,禁止手动创建Connection并调用commit()/rollback()。这些模板类会自动绑定到当前Spring事务上下文,统一受事务控制。 - 校验数据源与事务管理器:确认
service1和service2使用的是同一个数据源,且该数据源被Spring事务管理器(如DataSourceTransactionManager)正确配置管理。如果是多数据源场景,需在@Transactional注解中指定对应的事务管理器,确保两个服务的操作纳入同一事务。 - 排查异步逻辑:检查
service2.modifyDb()中是否存在异步执行的代码(如@Async注解的方法)。异步线程会脱离当前事务上下文,单独提交操作。需将异步逻辑调整到事务方法执行完成后,或给异步方法添加事务注解并通过事务同步机制处理。 - 检查全局事务配置:查看项目中是否存在全局事务拦截器、AOP切面等配置,是否给
service2的方法默认设置了REQUIRES_NEW等特殊事务传播特性。若有,需修改配置,确保默认传播特性为REQUIRED(Spring默认值),让service2的操作加入当前事务。
内容的提问来源于stack exchange,提问作者Amit Gupta
相关产品推荐
相关产品推荐

