Spring Boot中@Transactional方法无法回滚Hibernate数据库变更问题
Spring Boot 2.0.6 事务回滚失效问题排查与解决
问题背景
我在Spring Boot 2.0.6项目里碰到了个棘手的问题:有个标注@Service的ClassA类,它的methodA方法会调用另外两个@Service类(ClassB、ClassC)的方法,这两个方法分别通过Hibernate向数据库保存ObjectB和ObjectC实体,且都有可能抛出异常。我原本期望不管哪个Service方法抛出异常,所有数据库变更都能回滚——也就是删掉已创建的实体,但实际异常发生后,已做的变更依然留在数据库里。
代码重现
实体类
@Entity public class ObjectB{ @Id private long id; // 其他字段省略 } @Entity public class ObjectC{ @Id private long id; // 其他字段省略 }
服务类
@Service @Transactional public class ClassA{ @Autowired private ClassB classB; @Autowired private ClassC classC; public void methodA(){ classB.insertB(new ObjectB()); classC.insertC(new ObjectC()); } } @Service @Transactional public class ClassB{ @Autowired private RepositoryB repositoryB; public void insertB(ObjectB b){ repositoryB.save(b); } } @Service @Transactional public class ClassC{ @Autowired private RepositoryC repositoryC; public void insertC(ObjectC c){ repositoryC.save(c); } }
仓库类
@Repository public interface RepositoryB extends CrudRepository<ObjectB, String>{ } @Repository public interface RepositoryC extends CrudRepository<ObjectC, String>{ }
排查过程与解决办法
一开始我没对事务做任何特殊配置,但看控制台日志发现,每次调用方法都会创建新事务,抛出RuntimeException后却完全没回滚任何变更。
后来我补充检查了项目主类、pom.xml依赖以及application.properties配置,终于找到问题根源:用了不支持事务的MyISAM数据库引擎。MyISAM本身没有事务特性,哪怕Spring的事务配置看起来没问题,也没法实现回滚。
解决步骤很简单:
- 在
application.properties里添加Hibernate方言配置,指定使用支持事务的InnoDB引擎:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
- 删除数据库里现有的MyISAM引擎表,让JPA重新创建使用InnoDB引擎的表。
做完这两步后,事务回滚就正常生效了——只要有方法抛出RuntimeException,之前保存的实体都会被回滚删除。
额外注意事项
还有个容易踩坑的点:Spring的@Transactional注解默认只对RuntimeException及其子类异常触发回滚。如果你的方法抛出的是Checked Exception(非RuntimeException子类),默认不会触发回滚。这种情况需要手动指定回滚的异常类型,比如:
@Transactional(rollbackFor = Exception.class)
内容的提问来源于stack exchange,提问作者Stefano Sambruna
相关产品推荐
相关产品推荐

