Spring整合MyBatis时,两次数据库操作事务回滚失效问题求助
Spring+MyBatis事务不回滚问题排查与解决
看起来你遇到的核心问题是Spring事务默认不会对Checked Exception触发回滚,而你碰到的MySQLIntegrityConstraintViolationException恰好属于Checked Exception范畴,这就导致插入失败时删除操作没有被回滚。
问题原因分析
Spring的@Transactional注解默认回滚规则是:仅当抛出RuntimeException或Error时,才会触发事务回滚。而MySQLIntegrityConstraintViolationException继承自SQLException,属于Checked Exception,不在默认回滚的范围内。你的方法addRecord()声明抛出Exception,异常抛出后Spring事务管理器不会自动执行回滚逻辑。
解决方案
你需要显式通过@Transactional的rollbackFor属性指定需要触发回滚的异常类型,有两种常用方式:
1. 针对具体异常(推荐,更精准)
修改方法上的@Transactional注解,指定仅对MySQLIntegrityConstraintViolationException回滚:
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = MySQLIntegrityConstraintViolationException.class) public boolean addRecord() throws Exception { myMapper.deleteRecord(id); myMapper.insertRecord(- - -); return true; }
2. 针对所有Exception(适用于需要对所有异常回滚的场景)
如果希望任何Exception类型都触发回滚,可以直接指定rollbackFor = Exception.class:
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public boolean addRecord() throws Exception { myMapper.deleteRecord(id); myMapper.insertRecord(- - -); return true; }
额外验证点
除了修改注解,还要确认以下几点确保事务正常工作:
- 方法内部没有捕获并吞掉
MySQLIntegrityConstraintViolationException,必须让异常抛出到Spring事务代理层,事务管理器才能感知并触发回滚。 - 确保
SqlSessionFactoryBean使用的数据源和transactionManager()中的dataSource()是同一个实例,可在sqlSessionFactoryBean()方法中添加sessionFactory.setDataSource(dataSource());来明确绑定。 - 确认
@EnableTransactionManagement配置生效,你的配置中已经设置proxyTargetClass = true,且MyService被@Service注解标记,属于Spring容器管理的Bean,这部分是没问题的。
从你提供的日志来看,事务已经成功同步了SqlSession,但因为异常类型不在默认回滚范围内,所以没有执行回滚。修改rollbackFor属性后,插入失败时删除操作应该就能正常回滚了。
内容的提问来源于stack exchange,提问作者Pankaj
相关产品推荐
相关产品推荐

