@Transactional事务失效场景

@Transactional
事务失效场景

1、数据库引擎不支持事务

MyISAM 不支持事务,InnoDB 支持事务。

2、事务所在类没有被 spring 管理

没有注解注入等。

3、注解作用的方法,是非 public 的(方法无法被代理)

4、属性 rollbackFor 设置错误

事务机制默认是当捕获到 RuntimeException 异常时,才会触发回滚。所以当抛出 RuntimeException 以外的异常时,而又想触发事务的回滚机制,就需要对 rollbackFor 属性做设置了。
例如:
当 throw 了 Exception 异常时,想要触发事务回滚,就要设置@Transactional(rollbackFor = Exception.class)

5、属性 propagation 设置错误

通过设置 @Transactional(propagation = Propagation.NOT_SUPPORTED) 可以配置 Spring 的事务传播机制的,当事务传播机制设置为不支持事务是,事务也是不会生效的。
例如:
当设置为 propagation = Propagation.NOT_SUPPORTED 时,表示不以事务运行,当前若存在事务则挂起。

6、调用同类中的方法

因为事务是基于代理实现的,发生了直接的自我调用(类中方法调用内部方法),没有经过代理这种情况会造成程序无法生成代理类,从而造成事务失效。
具体的解决方法,可以将该类通过注入的方式注入到自己中,再用注入的对象调用方法解决。

7、异常被捕获,无法触发事务回滚

事务机制的回滚,是通过异常来触发事务回滚的。在开发过程中,会出现异常被捕获处理了,而且没有再抛出新的异常,就会导致异常丢失,无法触发回滚。

8、多线程调用

@Service
public class DemoService {
@Autowired
DemoTwoService demoTwoService;

@Transactional
public  void query(Demo demo) {
    new Thread(()->{
        demoTwoService.save(demo);
    }).start();
}

}

通过上面的例子,我们可以知道,query调用了事务方法save,但是事务方法在另一个线程里面调用,这样会导致两个方法在不同的一个线程中,获取的数据库连接也不一样,所以会是两个不同的事务,如果save的方法抛出了异常,query回滚是不可能的,看过spring源码,我们可以知道,spring的事务是通过连接数据库来实现的,当前线程保存了一个map,key—数据源,value—数据库连接,事务其实就是指向同一个连接的,只有拥有同一个数据库连接才能同时提交和回滚,如果在不同的线程,数据库的连接不是同一个,所以事务也不是同一个。

你可能感兴趣的:(java)