sping事务失效的几种场景
一.数据库引擎不支持事务
spring的事务需要底层数据库引擎的支持
这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。
根据 MySQL 的官方文档:
从 MySQL 5.5.5 开始的默认存储引擎是:InnoDB,之前默认的都是:MyISAM,所以这点要值得注意,底层引擎不支持事务再怎么搞都是白搭。
MySQL的几种引擎可以了解 https://www.cnblogs.com/zluckiy/p/13793799.html
二.在非public修饰的方法使用
以下来自 Spring 官方文档:
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
大概意思就是 @Transactional
只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ
代理模式。
代码中解释:
@Transactional注解使用的是AOP,在使用动态代理的时候只能针对public
方法进行代理,源码依据在AbstractFallbackTransactionAttributeSource
类中的computeTransactionAttribute
方法中,如下:
1 protected TransactionAttribute computeTransactionAttribute(Method method, 2 Class<?> targetClass) { 3 // Don't allow no-public methods as required. 4 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { 5 return null; 6 }
此处如果不是标注在public
修饰的方法上并不会抛出异常,但是会导致事务失效。
三.在try.catch代码段中,没有将异常抛出,导致事务无法回滚
1 @Transactional 2 public void method(){ 3 try{//错误不会回滚 4 //插入一条数据 5 //更改一条数据 6 }catch(Exception ex){ 7 return; 8 } 9 }
四.抛出的异常类型不对,默认为运行时异常RuntimeException
1 @Transactional 2 public void method(){ 3 try{ 4 //插入一条数据 5 //更改一条数据 6 }catch(Exception ex){ 7 return; 8 } 9 }
这样事务也是不生效的,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:
1 @Transactional(rollbackFor = Exception.class)
五.方法中调用同类的方法
1 public class Test{ 2 public void A(){ 3 //插入一条数据 4 //调用B方法 5 B(); 6 } 7 8 @Transactional 9 public void B(){ 10 //插入数据 11 } 12 }
简单的说就是一个类中的A方法
(未标注声明式事务)在内部调用了B方法
(标注了声明式事务),这样会导致B方法中的事务失效。
为什么会失效呢?:其实原因很简单,Spring在扫描Bean的时候会自动为标注了@Transactional
注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作,但是同类中的方法互相调用,相当于this.B()
,此时的B方法并非是代理类调用,而是直接通过原有的Bean直接调用,所以注解会失效。
六.配置错误导致事务失效
1.Propagation传播行为配置错误
spring默认的事务传播属性是Propagation.REQUIRED
,但是一旦配置了错误的传播属性,也是会导致事务失效,如下三种配置将会导致事务失效:
Propagation.SUPPORTS
Propagation.NOT_SUPPORTED
Propagation.NEVER
2代码中我们一般通过spring管理,去实现事务,需要注意代码块有没有被spring进行管理
3数据源没有配置事务管理器等配置相关的问题导致
参考https://javastack.blog.csdn.net/article/details/103871083
https://blog.csdn.net/qq_34162294/article/details/105803966