根据可能出现的情况排序,排查时可以从上往下排查
动态代理失效
@Transactional注解是基于AOP的,AOP基于动态代理,如果动态代理失效,那么@Transactional就会失效。动态代理失效的场景如下:
- 事务方法是private方法:private修饰的方法,只能在类中使用,也就是this调用,这种情况是不会走到代理对象的,所以代理失效,从而事务失效。
- 事务方法是类内部方法:自己调自己,逻辑同private方法,代理对象是调不到的
- 事务方法是static方法:static是类方法,不对对象方法,但是动态代理代理的是对象,所以static方法是没办法被AOP的
- 事务方法是final方法:final方法是不可被修改的,换句话说是没办法覆盖的,没办法被AOP
异常被捕获
如果在事务方法内把异常给捕获了,自己处理了,那么事务方法会认为这个方法应该被commit,从而就不会触发事务回滚。
public class TestService{
@Transactional
public void test() {
try {
// 业务逻辑
doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
例如以上,如果doSomething()方法抛出异常,添加了事务注解的test()方法中捕获了异常,进行了处理,那么事务就会被commit,那么事务就不可能被回滚了
注解属性用的不对
最容易用错的属性是以下两个
rollbackFor属性
rollbackFor属性指定发生什么类型的异常会触发事务回滚。一般设置成**rollbackFor= MyException.class**
。
这样出现非受检异常时,也可以触发事务回滚。
propagation属性
propagation属性指的是事务传播行为,Spring默认传播行为是REQUIRED,一般我们不用设置这个属性,使用默认的即可。如果使用**propagation = Propagation.NOT_SUPPORTED**
就会导致事务失效,原因是Propagation.NOT_SUPPORTED以非事务的方式运行,如果当前存在事务,暂停当前的事务。
数据库引擎不支持
出现了这种情况的可能性比较少,目前主流的数据库是MySQL,MySQL默认的存储引擎是InnoDB,是支持事务的。Myisam等其他不支持事务的存储引擎比较少用。