为啥Spring事务失效了,你踩坑了吗?
hello,慕仔们,我们又见面了。前段时间小慕做的智慧社区门禁服务的业务中恰好遇上了事务失效的场景,于是就有了今天的这篇文档总结,避免让慕仔们踩坑。
今天我们不聊微服务架构下的分布式事务,只谈单体应用系统下的事务,那到底哪些情况下会导致事务失效呢?咱们现在就来唠嗑唠嗑吧!
1. 底层数据库引擎不支持事务
以MySQL为例,MyISAM引擎不支持事务操作,InnoDB引擎支持事务,MySQL从5.5.5开始默认的引擎是InnoDB,之前的版本默认的都是MyISAM,所以这个要注意。
2. 被@Transactional 注解修饰的方法为非public类型
如果被@Transactional注解修饰的方法,修饰符非public或者被final修饰,则事务会失效,因为AOP没办法为这样的方法生成一个代理,自然事务就无法生效。这个在Spring的官方文档里面也有说明。
3. 异常被吃掉了
如果异常被 catch 住,那事务也是会失效呢,伪代码如下
@Transactional
public void test(){
try{
//插入一条数据
insertData();
//更改一条数据
updateData();
}catch(Exception e){
log.error("异常被捕获,事务失效",e);
}
}
4. 异常抛出类型错误
@Transactional 注解有个属性:rollbackFor,这个属性可以设置想要回滚的异常类型,那它默认的异常类型是什么?立即回答:RuntimeException,太棒了。
如果说我们没有设置这个属性,而且抛出的异常比这个大,那么事务就不会回滚,例如:
@Transactional
public void test(){
try{
//插入一条数据
insertData();
//更改一条数据
updateData();
}catch(Exception e){
// 这个时候事务就不会回滚,
throw new Exception("操作失败!");
}
}
5. 本类方法调用
这一个应该是最容易踩坑的了,也是小慕踩坑的地方,先来看两段伪代码:
代码一:
@Service
public class TestServiceImpl implements TestService {
public void testA() {
// 查询数据,并进行一些判断
// 调用本类的另外一个方法
testB();
}
@Transactional
public void testB(Test test) {
// update test
}
}
小慕提问:testA()方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 testB() 方法,testB() 方法上的事务管用吗?
代码二:
@Service
public 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提供的事务管理了,事务自然就不生效。
半山腰总是最挤的,你得去山顶上瞅瞅,拜拜
好,今天的内容就分享到这里了,你们一定要变优秀哦,我们下期再见。
历史推文
点击蓝字
喜欢就点关注 和右下角的“在看”吧,比心