原文链接:https://blog.csdn.net/hzj_java/article/details/113098631
1. 底层数据库引擎不支持事务以MySQL为例,它有多种引擎,MyISAM引擎不支持事务操作,InnoDB引擎支持事务,MySQL从5.5.5开始默认的引擎是InnoDB,之前的版本默认的都是MyISAM,所以说如果是非常老的项目,这个需要考虑下。
2. 被@Transactional 注解修饰的方法为非public类型如果被@Transactional注解修饰的方法,修饰符非public或者被final修饰,则事务会失效,因为AOP没办法为这样的方法生成一个代理,自然事务就无法生效。这个在Spring的官方文档里面也有说明。
在这个地方有个详细讨论过程:https://stackoverflow.com/questions/4396284/does-spring-transactional-attribute-work-on-a-private-method
3.异常被捕获了如果异常被 catch 住,那事务也是会失效呢,伪代码如下:
@Transactional
public void test(){
try{
//插入一条数据
insertA();
//更改一条数据
updateB();
}catch(Exception e){
log.error("异常被捕获了,事务就失效了",e);
}
}
4,异常抛出类型错误
@Transactional 注解有个属性:rollbackFor,这个属性可以设置想要回滚的异常,那它默认的异常是什么?
不要犹豫直接告诉我答案,它默认回滚的是:RuntimeException,如果说我们没有设置这个属性,而且抛出的异常比这个大,那么事务就不会回滚,例如:
@Transactional
public void test(){
try{
//插入一条数据
insertA();
//更改一条数据
updateB();
}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
}
}
@Service
public class TestServiceImpl implements TestService {
@Transactional
public void testA() {
// 查询数据,并进行一些判断
// 调用另外一个方法
testB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testB(Test test) {
// update test
}
}
testB() 方法上的事务是不管用的。
因为他们是本类方法直接调用,这个时候会用this关键字,没有经过 Spring 的代理类去调用此方法,从而没有开启事务管理,默认只有在外部调用事务才会生效。
所以说:加事务注解的方法给本类里面的方法调用,事务不生效!
有多种解决方法:
6,没有被spring管理
- 最直白的就是把方法拆出来,放在两个类里面(Spring推荐的一种方式);
- 在类里面注入自己,用注入的对象再调用另外一个方法,这个不太优雅;
- 在Spring的配置里面增加一段配置:
当这个类只是一个普通类,没有被spring管理成为一个Bean对象,那它很自然的就不能使用spring提供的事务管理了,事务自然就不生效。例如:把@Service注解去掉,这个时候事务就不会生效,小伙伴们可以试试。
总结以上列举了几种常见的事务失效的原因,其实发生最多就是异常被捕获了、异常抛出类型错误、本类方法调用不对这三个了,这三点只要在日常码代码的时候注意一下,基本就不会有问题了。



