spring的@Transactional失效原因分析
Posted 好大的月亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring的@Transactional失效原因分析相关的知识,希望对你有一定的参考价值。
在测试环境遇到了一次@Transactional
事务失效的场景,将排查的方式记录下来。
一开始以为是aop
的其他代理类影响到了,但是后面取消代理类后事务还是没有生效。尝试在插入的方法中单独加@Transactional
注解但是也没生效。一般我们记忆中只要抛了异常,并且这个异常确保是可以被回滚的,那么事务是可以回滚的。但是这里明显没有回滚。
接下来就是打断点debug
了,发现当进入方法,执行插入数据库的那一行代码之后,数据直接用navicat
就可以查到了,说明压根没有开启事务,如果有事务的话方法都没结束事务也就没提交,navicat
在默认的事务隔离级别下是查不到数据的。
到这里初步排查出来事务没有生效,此时只要排查下数据库表的ENGINE
是不是innodb
,再一个就是自动注入的是 PlatformTransactionManager
接口的哪个实现类。
因为事务管理器,不管是JPA
还是JDBC
等都实现自接口 PlatformTransactionManager
.如果你添加的是 spring-boot-starter-jdbc
依赖,框架会默认注入 DataSourceTransactionManager
实例(mybatis
也是注入的这个实例)。如果你添加的是 spring-boot-starter-data-jpa
依赖,框架会默认注入 JpaTransactionManager
实例。
实际注入的PlatformTransactionManager
实例可以这样查看
@EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication {
@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager){
System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
return new Object();
}
public static void main(String[] args) {
SpringApplication.run(ProfiledemoApplication.class, args);
}
}
这里参考了大佬的博文
https://blog.csdn.net/catoop/article/details/50595702
https://zhuanlan.zhihu.com/p/145897825
其他的常见的事务失效场景一般就这几种:
@Transactional
应用在非public
修饰的方法上,aop只能在public方法上切@Transactional
注解属性propagation
设置错误,传播的值没搞对,导致事务没有传递进实际增删改的方法里@Transactional
注解属性rollbackFor
设置错误,这个就是抛出的异常没配置好,默认是RuntimeException
,也可以自己自定义,只要异常是继承自rollbackFor
指定的异常,都能回滚- 同一个类中方法调用,导致
@Transactional
失效,比如就是controller
里先调用了一个方法,然后在这个方法里再调用@Transactional
声明的方法,这个时候是因为先调用的时候用的是没有被aop
代理的类,然后调用这个类的其他方法的时候默认使用了this
关键字指向了当前对象,没有指向代理的类 - 异常被你的
catch
“吃了”导致@Transactional
失效 - 数据库引擎不支持事务,我遇到的就是这种,
myisam
是不支持事务的,只有innodb
引擎支持事务
以上是关于spring的@Transactional失效原因分析的主要内容,如果未能解决你的问题,请参考以下文章