事务失效场景

​ 事务失效场景

  1. 一个有@Transactional的方法被没有@Transactional方法调用时,会导致Transactional作用失效。也是最容易出现的情况。

    ​ 那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象管理

  2. 对非public方法进行事务注解。@Transactional 将会失效

原因:是应为在Spring AOP代理时,事务拦截器在目标方法前后进行拦截,DynamicAdvisedInterceptor的intercept 方法会获取Transactional注解的事务配置信息,

因为在Spring AOP 代理时,如上图所示 TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSourcecomputeTransactionAttribute 方法会间接调用 AbstractFallbackTransactionAttributeSourcecomputeTransactionAttribute 方法,这个方法会获取Transactional 注解的事务配置信息。他会首先校验事务方法的修饰符是不是public,不是 public则不会获取@Transactional 的属性配置信息。

  1. Transactional 事务配置属性中的propagation 属性配置的问题。

 当propagation属性配置为:

TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。       TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常

  1. 还存在一种情况

  在一个类中A方法被事务注释,B方法也被事务注释。

1
2
3
4
5
6
7
8
@Transactional
 public void A(){
  try{
  this.B();
  }catch(Exception e){
    logger.error();
  }
}

但在执行B方法是报错,但是异常被A catch 住,此时事务也会失效。

底层原理

其实原因很简单,Spring在扫描Bean的时候会自动为标注了@Transactional注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作,但是同类中的方法互相调用,相当于this.B(),此时的B方法并非是代理类调用,而是直接通过原有的Bean直接调用,所以注解会失效。

spring事务的传播机制及原因分析;

propagation_required 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。