Spring Boot对接MS SQL时@Transactional未开启事务导致回滚失效问题
Spring Boot @Transactional事务不生效的解决办法
你遇到的问题是Spring声明式事务的三个典型使用误区导致的:
- 同类方法自调用导致事务注解失效
Spring的声明式事务基于AOP动态代理实现,只有外部调用代理对象的标注了@Transactional的方法时,事务切面才会触发。你在同一个Service的scheduledIteration方法里直接通过this调用insertDataInNewTransaction,属于原对象的内部调用,不会走代理逻辑,事务完全没有开启,所有数据库操作都是自动提交的,抛出异常自然不会回滚。 - 事务方法修饰符不符合要求
Spring AOP默认仅对public修饰的方法生成代理,你将事务方法定义为protected,对应的@Transactional注解不会被切面识别,就算是外部调用也不会生效。 - 传播属性不符合"开启新事务"的诉求
你当前使用的Propagation.REQUIRED逻辑为"存在当前事务则加入,不存在才新建",如果你需要该方法每次调用都独立开启新事务,应该调整为Propagation.REQUIRES_NEW。
解决方案
- 将
insertDataInNewTransaction方法的修饰符修改为public - 避免同类内部直接调用事务方法,两种可选方案:
- 将事务方法抽取到独立的Service Bean中,在当前Service中注入该Bean后调用
- 在当前类中注入自身的代理对象,通过代理对象调用事务方法,参考代码如下:
@Service public class SomeService { // 注入自身代理对象 @Autowired private SomeService self; SomeRepository repository; public SomeService(SomeRepository someRepository) { this.repository = someRepository; } @Scheduled(fixedDelayString="${property}") //10 seconds protected void scheduledIteration() { if(something) { // 通过代理对象调用事务方法 self.insertDataInNewTransaction(getSomeData()); } } @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public void insertDataInNewTransaction(List<Data> data) { // 原有业务逻辑 repository.saveAll(data); repository.verifyData(); } } - 删除你添加的
spring.datasource.hikari.auto-commit=false、spring.datasource.auto-commit=false配置,Spring事务管理器会自动接管数据库连接的提交、回滚逻辑,不需要额外手动关闭自动提交。
调整完成后重新测试,抛出异常时之前插入的数据就会正常回滚,在事务未提交阶段,数据库默认的读提交隔离级别下也无法查到未提交的插入数据。
内容的提问来源于stack exchange,提问作者CSB
相关产品推荐
相关产品推荐

