为啥Spring事务失效了,你踩坑了吗?

  hello,慕仔们,我们又见面了。图片图片图片前段时间小慕做的智慧社区门禁服务的业务中恰好遇上了事务失效的场景,于是就有了今天的这篇文档总结,避免让慕仔们踩坑。图片图片

 今天我们不聊微服务架构下的分布式事务,只谈单体应用系统下的事务,那到底哪些情况下会导致事务失效呢?咱们现在就来唠嗑唠嗑吧!

   

    

1. 底层数据库引擎不支持事务

以MySQL为例,MyISAM引擎不支持事务操作,InnoDB引擎支持事务,MySQL从5.5.5开始默认的引擎是InnoDB,之前的版本默认的都是MyISAM,所以这个要注意。

 

2. 被@Transactional 注解修饰的方法为非public类型

如果被@Transactional注解修饰的方法,修饰符非public或者被final修饰,则事务会失效,因为AOP没办法为这样的方法生成一个代理,自然事务就无法生效。这个在Spring的官方文档里面也有说明。

 

3. 异常被吃掉了

如果异常被 catch 住,那事务也是会失效呢,伪代码如下

@Transactionalpublic void test(){  try{    //插入一条数据    insertData();    //更改一条数据    updateData();  }catch(Exception e){    log.error("异常被捕获,事务失效",e);  }}

 

 

4. 异常抛出类型错误

@Transactional 注解有个属性:rollbackFor,这个属性可以设置想要回滚的异常类型,那它默认的异常类型是什么?立即回答:RuntimeException,太棒了。

如果说我们没有设置这个属性,而且抛出的异常比这个大,那么事务就不会回滚,例如:

@Transactionalpublic void test(){  try{    //插入一条数据    insertData();    //更改一条数据    updateData();  }catch(Exception e){    // 这个时候事务就不会回滚,    throw new Exception("操作失败!");  }}

 

5. 本类方法调用

这一个应该是最容易踩坑的了,也是小慕踩坑的地方,先来看两段伪代码:

代码一:

@Servicepublic class TestServiceImpl implements TestService {   public void testA() {        // 查询数据,并进行一些判断        // 调用本类的另外一个方法        testB();    }   @Transactional
   public void testB(Test test) {        // update test    }}

小慕提问图片:testA()方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 testB() 方法,testB() 方法上的事务管用吗?

 

代码二:

@Servicepublic class TestServiceImpl implements TestService {   @Transactional
   public void testA() {        // 查询数据,并进行一些判断        // 调用另外一个方法        testB();    }
  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void testB(Test test) {        // update test    }}

小慕提问图片:在 testA() 方法上加了 @Transactional,testB() 的注解上加了 REQUIRES_NEW 新开启一个事务,那么新开的事务管用么?

 

立即推,以上两段代码的事务都不生效,答对了吧,答对的小伙伴手动@我,找我领红包,图片图片图片

为啥会失效,因为他们是本类的方法直接调用,这个时候会用this关键字,没有经过 Spring 的代理类去调用此方法,从而没有开启事务管理,默认只有在外部调用事务才会生效。

 

总结::加事务注解的方法给本类里面的方法调用,事务不生效!

 

话又说回来了,那怎么解决这个问题呢?小慕提供3种解决方案

解法一::最直白的就是把方法拆出来,放在两个类里面(Spring推荐的一种方式);

 

解法二:在类里面注入自己,用注入的对象再调用另外一个方法,这个不太优雅;

 

解法三:在Spring的配置里面增加一段配置  :

   <aop:aspectj-autoproxyexpose-proxy="true"/>

 

 

6、没有被spring管理

当这个类只是一个普通类,没有被spring管理成为一个Bean对象,那它很自然的就不能使用spring提供的事务管理了,事务自然就不生效。

 

半山腰总是最挤的,你得去山顶上瞅瞅,拜拜图片图片图片

好,今天的内容就分享到这里了,你们一定要变优秀哦,我们下期再见。

现在公众号迁移到这个啦, 不要迷路了,慕仔们,加油哦!

       接下来的一段时间,我会专注Java技术栈,计算机网络,数据结构和算法,操作系统,设计模式,计算机组成原理,数据库原理,设计模式来做分享,欢迎你们和我一起学习,一起提高,Fighting!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java全栈研发大联盟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值