(Spring)事务源码解析

178 阅读6分钟

先看几种事务使用场景

@Transactional(rollbackFor = Exception.class)
public void test() {
   jdbcTemplate.execute("insert into t_user values(1,'张三') ");
   aa();


}

@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void aa(){
   jdbcTemplate.execute("insert into t_user values(2,'李四') ");
}

test()方法事务传播机制是Propagation.REQUIRED,aa()方法事务传播机制是Propagation.REQUIRES_NEW,在test()中调用了aa(),实际情况下呢是aa()的事务并不会生效。

@Transactional(rollbackFor = Exception.class)
public void test() {
   jdbcTemplate.execute("insert into t_user values(1,'张三') ");
   try {
      userService.aa();
   } catch (Exception e){

   }
}

@Transactional(rollbackFor = Exception.class)
public void aa(){
   jdbcTemplate.execute("insert into t_user values(2,'李四') ");
   throw new NullPointerException();
}

这里将aa()方法事务传播机制改为同test(),同时test()中并没有直接调用aa(),而是注入当前类去调用,使test()中调用了aa(),让aa()的事务生效,test()中包裹异常,执行最后的结果是插入1条还是2条还是0条。
答案是0条。

理论

先说理论再看源码,使用事务需要先用@EnableTransactionManagement注解去开启事务,然后在想使用事务的方法或者类上加上@Transactional注解,Transactional带来的作用:

  1. spring启动中生成代理对象,原始对象在属性target中
  2. 代理对象.test()
  3. spring事务管理器,创建数据库连接
  4. conn.autocommit=false 关闭自动提交
  5. 设置隔离级别
  6. conn放入ThreadLocal<Map<>> DataSource,conn连接
  7. target.test() 执行真正的test()方法
  8. 提交/回滚

场景一

结合上面的步骤来看场景一的调用链路是这样的:
代理对象.test() -> target.test() -> target.aa()
设置隔离级别这一步骤是在代理对象调用方法之后才会有的,只需要自己注入自己(注入进来的userService也同样是代理对象)调用链路就变成了:
代理对象.test() -> target.test() -> 代理对象.aa() -> target.aa()

场景二

先看调用链路:
代理对象.test() -> target.test() -> 代理对象.aa() -> target.aa() -> 出现异常回滚
这里误区主要在异常是aa()抛出的,test()已经try-catch了,为什么test()也随着回滚了,这里要先搞明白他们的传播机制都是Propagation.REQUIRED,也就是在同一个事务中,同一个事务也就意味着conn连接用的同一个,aa()的conn进行了回滚操作,test()也会随着回滚(spring中可以修改这个为分段式回滚,修改后则不会出现这种情况,但是一般不推荐这么做)。

源码

@EnableTransactionManagement

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

   /**
    * Returns {@link ProxyTransactionManagementConfiguration} or
    * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
    * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
    * respectively.
    */
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY:
            // 默认是PROXY
            return new String[] {AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ:
            // 表示不用动态代理技术,用ASPECTJ技术,比较麻烦了
            return new String[] {determineTransactionAspectClass()};
         default:
            return null;
      }
   }

   private String determineTransactionAspectClass() {
      return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
            TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
            TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
   }

}

开启Spring事务本质上就是增加了一个Advisor,但我们使用@EnableTransactionManagement注解来开启Spring事务,该注解代理的功能就是向Spring容器中添加了两个Bean:

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

AutoProxyRegistrar主要的作用是向Spring容器中注册了一个InfrastructureAdvisorAutoProxyCreator的Bean。 而InfrastructureAdvisorAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator,所以这个类的主要作用就是开启自动代理的作用,也就是一个BeanPostProcessor,会在初始化后步骤中去寻找Advisor类型的Bean,并判断当前某个Bean是否有匹配的Advisor,是否需要利用动态代理产生一个代理对象。
ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

  1. BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor
  2. AnnotationTransactionAttributeSource:相当于BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut
  3. TransactionInterceptor:相当于BeanFactoryTransactionAttributeSourceAdvisor中的 Advice

AnnotationTransactionAttributeSource就是用来判断某个类上是否存在@Transactional注解,或者判断某个方法上是否存在@Transactional注解的。TransactionInterceptor就是代理逻辑,当某个类中存在@Transactional注解时,到时就产生一个 代理对象作为Bean,代理对象在执行某个方法时,最终就会进入到TransactionInterceptor的 invoke()方法。

TransactionInterceptor#invoke

TransactionInterceptor对于MethodInterceptor#invoke的实现很简单,就是调用父类的的invokeWithinTransaction,并传递给此方法一个回调用于继续后续的拦截调用。

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
   // Work out the target class: may be {@code null}.
   // The TransactionAttributeSource should be passed the target class
   // as well as the method, which may be from an interface.
   Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

   // Adapt to TransactionAspectSupport's invokeWithinTransaction...
   return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
      @Override
      @Nullable
      public Object proceedWithInvocation() throws Throwable {
         // 执行后续的Interceptor,以及被代理的方法
         return invocation.proceed(); // test() sql
      }
      @Override
      public Object getTarget() {
         return invocation.getThis();
      }
      @Override
      public Object[] getArguments() {
         return invocation.getArguments();
      }
   });
}

TransactionAspectSupport#invokeWithinTransaction

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {

   // If the transaction attribute is null, the method is non-transactional.
   // TransactionAttribute就是@Transactional中的配置
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 获取@Transactional注解中的属性值
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

   // 返回Spring容器中类型为TransactionManager的Bean对象
   final TransactionManager tm = determineTransactionManager(txAttr);

   // ReactiveTransactionManager用得少,并且它只是执行方式是响应式的,原理流程和普通的是一样的
   if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
      boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
      boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
            COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
      if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
         throw new IllegalStateException("Coroutines invocation not supported: " + method);
      }
      CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);

      ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
         Class<?> reactiveType =
               (isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
         ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
         if (adapter == null) {
            throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
                  method.getReturnType());
         }
         return new ReactiveTransactionSupport(adapter);
      });

      InvocationCallback callback = invocation;
      if (corInv != null) {
         callback = () -> CoroutinesUtils.invokeSuspendingFunction(method, corInv.getTarget(), corInv.getArguments());
      }
      Object result = txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, (ReactiveTransactionManager) tm);
      if (corInv != null) {
         Publisher<?> pr = (Publisher<?>) result;
         return (hasSuspendingFlowReturnType ? KotlinDelegate.asFlow(pr) :
               KotlinDelegate.awaitSingleOrNull(pr, corInv.getContinuation()));
      }
      return result;
   }

   // 把tm强制转换为PlatformTransactionManager,所以我们在定义时得定义PlatformTransactionManager类型
   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);

   // joinpoint的唯一标识,就是当前在执行的方法名字
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   // CallbackPreferringPlatformTransactionManager表示拥有回调功能的PlatformTransactionManager,也不常用
   if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
      // 如果有必要就创建事务,这里就涉及到事务传播机制的实现了
      // TransactionInfo表示一个逻辑事务,比如两个逻辑事务属于同一个物理事务
      TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

      Object retVal;
      try {
         // This is an around advice: Invoke the next interceptor in the chain.
         // This will normally result in a target object being invoked.
         // 执行下一个Interceptor或被代理对象中的方法
         retVal = invocation.proceedWithInvocation(); //test
      }
      catch (Throwable ex) {
         // target invocation exception
         // 抛异常了,则回滚事务,或者
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         cleanupTransactionInfo(txInfo);
      }

      if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
         // Set rollback-only in case of Vavr failure matching our rollback rules...
         TransactionStatus status = txInfo.getTransactionStatus();
         if (status != null && txAttr != null) {
            retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
         }
      }

      // 提交事务
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }

   else {
      Object result;
      final ThrowableHolder throwableHolder = new ThrowableHolder();

      // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
      try {
         result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
            TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
            try {
               Object retVal = invocation.proceedWithInvocation();
               if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
                  // Set rollback-only in case of Vavr failure matching our rollback rules...
                  retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
               }
               return retVal;
            }
            catch (Throwable ex) {
               if (txAttr.rollbackOn(ex)) {
                  // A RuntimeException: will lead to a rollback.
                  if (ex instanceof RuntimeException) {
                     throw (RuntimeException) ex;
                  }
                  else {
                     throw new ThrowableHolderException(ex);
                  }
               }
               else {
                  // A normal return value: will lead to a commit.
                  throwableHolder.throwable = ex;
                  return null;
               }
            }
            finally {
               cleanupTransactionInfo(txInfo);
            }
         });
      }
      catch (ThrowableHolderException ex) {
         throw ex.getCause();
      }
      catch (TransactionSystemException ex2) {
         if (throwableHolder.throwable != null) {
            logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
            ex2.initApplicationException(throwableHolder.throwable);
         }
         throw ex2;
      }
      catch (Throwable ex2) {
         if (throwableHolder.throwable != null) {
            logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
         }
         throw ex2;
      }

      // Check result state: It might indicate a Throwable to rethrow.
      if (throwableHolder.throwable != null) {
         throw throwableHolder.throwable;
      }
      return result;
   }
}

 TransactionAspectSupport#createTransactionIfNecessary

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

   // 如果事务属性中name为null,则创建一个简易委托类,name为连接点方法标识。
   if (txAttr != null && txAttr.getName() == null) {
      txAttr = new DelegatingTransactionAttribute(txAttr) {
         @Override
         public String getName() {
            return joinpointIdentification;
         }
      };
   }

   // 每个逻辑事务都会创建一个TransactionStatus,但是TransactionStatus中有一个属性代表当前逻辑事务底层的物理事务是不是新的
   TransactionStatus status = null;
   if (txAttr != null) {
      if (tm != null) {
         // 根据事务属性判断是否需要开启事务,并返回状态。
         status = tm.getTransaction(txAttr);
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                  "] because no transaction manager has been configured");
         }
      }
   }

   // 返回一个TransactionInfo对象,表示得到了一个事务,可能是新创建的一个事务,也可能是拿到的已有的事务
   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}