spring源码分析之事务transaction上篇

spring源码分析之事务transaction上篇

大家基本上都用过事务,今天一起分析下spring源码中也比较重要的一个模块-事务。spring中事务这一块要完全使用好还是有一定难度,主要是很多细节需要注意,如果你还没有完全明白spring的事务,那么这篇文章肯定会让你收获满满。

一、创建代理

spring事务创建代理的流程和spring aop创建代理几乎是一模一样,不清楚的可以自行阅读相关资料或者参考这篇文章(spring aop分析)。这里稍微介绍创建代理之前spring会先创建几个重要的对象

我们从@EnableTransactionManagement这个事务的开关的入口开始

1.@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
   }

不多讲,直接看@Import里面的类,如果不明白的,可以阅读这篇文章(spring源码解析之ConfigurationClassPostProcessor分析

2.TransactionManagementConfigurationSelector
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) {
   
          //默认是PROXY,spring会讲该方法返回的string[]都实例化
         case PROXY:
            return new String[] {
   AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ:
            return new String[] {
   determineTransactionAspectClass()};
         default:
            return null;
      }
   }
    //...省略
}

所以到这里,spring会实例化一个AutoProxyRegistrar对象和ProxyTransactionManagementConfiguration对象,其中AutoProxyRegistrar和AOP创建那个拦截是否需要代理的BeanpostProcessor一样,这里就不继续跟,感兴趣自行阅读。我们看ProxyTransactionManagementConfiguration。

3.ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
   

   @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
         TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
   

      BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
      advisor.setTransactionAttributeSource(transactionAttributeSource);
      advisor.setAdvice(transactionInterceptor);
      if (this.enableTx != null) {
   
         advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
      }
      return advisor;
   }

   @Bean
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public TransactionAttributeSource transactionAttributeSource() {
   
      return new AnnotationTransactionAttributeSource();
   }

   @Bean
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
   
      TransactionInterceptor interceptor = new TransactionInterceptor();
      interceptor.setTransactionAttributeSource(transactionAttributeSource);
      if (this.txManager != null) {
   
         interceptor.setTransactionManager(this.txManager);
      }
      return interceptor;
   }

}

这里会创建三个对应的三个实例

BeanFactoryTransactionAttributeSourceAdvisor:是一个advisor,一般封装advice和pointcut

TransactionAttributeSource:用于解析事务标签属性

TransactionInterceptor:这个最重要,直接就是动态代理的调用的方法,其实现了MethodInterceptor接口。所以当调用生成的动态代理的方法时,会调用到TransactionInterceptor.invoke()方法,这也是我们今天分析的入口。其他的流程和springAOP流程一致,可自行阅读

二、创建事务源码分析

直接从TransactionInterceptor#invoke()开始分析

1.TransactionInterceptor.invoke()
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, invocation::proceed);
}

直接过,看invokeWithinTransaction

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

   // If the transaction attribute is null, the method is non-transactional.
   TransactionAttributeSource tas = getTransactionAttributeSource();
    //通过TransactionAttributeSource获取@Transactional注解中的属性
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    //获取事务管理器
   final TransactionManager tm = determineTransactionManager(txAttr);
//这个if一般不会走到
   if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
   }

   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
   
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
       //1.这是创建事务的核心逻辑,非常重要
      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.
          //2.调用真是的业务逻辑
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
   
         // target invocation exception
          //3.核心逻辑之一,事务回滚
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
   
         cleanupTransactionInfo(txInfo);
      }

      if (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);
         }
      }
		//4.核心逻辑之一,事务提交
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }

 //...省略代码,暂时先不看
}

事务-主要处理的逻辑如下

创建事务、调用业务逻辑、事务回滚、事务提交我们一个个来看,spring事务中隔离级别和mysql的隔离级别是一致的,但是spring中的传播属性是spring实现的,这就是难点之一,我们今天重点看的是如何正确处理好传播属性。分析之前,先描述下spring支持哪7重传播属性

REQUIRED:如有事务,则使用当前事务,没有则创建

SUPPORTS:如果有事务,就用当前事务;没有则不适用事务

MANDATORY:使用当前事务,如果当前事务没有则抛异常

REQUIRES_NEW:新建事务,如果当前存在事务,则将当前事务挂起

NOT_SUPPORTED:非事务方式执行,如果当前存在事务 ,就将当前事务挂起

NEVER:非事务方式执行,如果当前存在事务 ,就抛异常

NESTED:嵌套事务

其实最常用的就是REQUIRED(默认)、REQUIRES_NEW、NESTED,今天源码分析也只分析上面三种,也是最复杂的三种

本文以我下面的测试的代码为例子,进行分析

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public void testInsert() throws Exception {
   
    String sql = "insert into user (name,age,sex) values(?,?,?)";
    jdbcTemplate.update(sql,new Object[]{
   "taott11",12,"man"});
    //int a = 1/0;
    //throw new Exception();
    String sql2 = "insert into user (name,age,sex) values(?,?,?)";
    jdbcTemplate.update(sql2,new Object[]{
   "tao",18,"woman"});
    //这里又调用了另外一个有事务标记的方法(动态代理方法)
    productService.queryUesr();
}
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED)
public void queryUesr() throws Exception {
   
    query();
    throw new RuntimeException();
}

上述实例会调用两次动态代理的方法,一次是UserService.testInsert(),另外一次是ProductService.queryUesr(),请忽略类名和方法名,没任何含义,仅仅是测试使用而已

我们先从第一个代理方法开始进入分析,调用业务方法testInsert()之前先创建事务

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

   // If no name specified, apply method identification as transaction name.
   if (txAttr != null && txAttr.getName() == null) {
   
      txAttr = new DelegatingTransactionAttribute(txAttr) {
   
         @Override
         public String getName() {
   
             //获取完成方法名
            return joinpointIdentification;
         }
      };
   }

   TransactionStatus status = null;
   if (txAttr != null) {
   
      if (tm != null) {
   
          //1.核心逻辑
         status = tm.getTransaction(txAttr);
      }
      else {
   
         if (logger.isDebugEnabled()) {
   
            logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                  "] because no transaction manager has been configured");
         }
      }
   }
   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

没什么重要的逻辑,我们重点看tm.getTransaction()

4.AbstractPlatformTransactionManager.getTransaction()
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
      throws TransactionException {
   

   // Use defaults if no transaction definition given.
   TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
	//1.创建一个事务对象
   Object transaction = doGetTransaction();
   boolean debugEnabled = logger.isDebugEnabled();
	//2.判断是否已经存在事务,第一次调用testInsert没有,第二次就有了,非常重要的方法
   if (isExistingTransaction(transaction)) {
   
      // Existing transaction found -> check propagation behavior to find out how to behave.
      return handleExistingTransaction(def, transaction, debugEnabled);
   }

   // Check definition settings for new transaction.
   if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
   
      throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
   }

   // No existing transaction found -> check propagation behavior to find out how to proceed.
   if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
   
      throw new IllegalTransactionStateException(
            "No existing transaction found for transaction marked with propagation 'mandatory'");
   }
   else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
         def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
         def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
   
      SuspendedResourcesHolder suspendedResources = suspend(null);
      if (debugEnabled) {
   
         logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
      }
      try {
   
          //3.开启事务
         return startTransaction(def, transaction, debugEnabled, suspendedResources);
      }
      catch (RuntimeException | Error ex) {
   
         resume(null, suspendedResources);
         throw ex;
      }
   }
   else {
   
      // Create "empty" transaction: no actual transaction, but potentially synchronization.
      if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
   
         logger.warn("Custom isolation level specified but no actual transaction initiated; " +
               "isolation level will effectively be ignored: " + def);
      }
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
   }
}

重要的逻辑方法,我已经做了标注了,下面我们一个个看

4-1.doGetTransaction()

创建事务对象

protected Object doGetTransaction() {
   
   DataSourceTransactionObject txObject = new DataSourceTransactionObject();
   txObject.setSavepointAllowed(isNestedTransactionAllowed());
    //这个地方拿到数据库的连接,其实是从threadlocal中拿,第一次拿不到,因为没有设置进去,后面会详细将
   ConnectionHolder conHolder =
         (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    //所以这个事务的连接其实是null
   txObject.setConnectionHolder(conHolder, false);
   return txObject;
}

第一次不会走到上面代码4中的注释2,因为不存在事务。所以我们直接看注释3,开启事务startTransaction

4-2.startTransaction()
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
      boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
   

   boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    //创建了一个事务状态,请记住第三个参数为true,后面会用到
   DefaultTransactionStatus status = newTransactionStatus(
         definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    //开怎么开启事务的
   doBegin(transaction, definition);
   prepareSynchronization(status, definition);
   return status;
}

这里就是创建了一个DefaultTransactionStatus,这里第三个参数newTransaction=true希望大家先记住,这是spring事务的一个非常重要的细节,后面的提交和回滚都和参数有联系,只有该参数为true的条件下的事务才有资格提交和回滚,下面我们看doBegin

4-2-1.doBegin()
protected void doBegin(Object transaction, TransactionDefinition definition) {
   
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   Connection con = null;

   try {
   
       //1.给当前事务设置连接
      if (!txObject.hasConnectionHolder() ||
            txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
   
         Connection newCon = obtainDataSource().getConnection();
         if (logger.isDebugEnabled()) {
   
            logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
         }
         txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
      }

      txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
      con = txObject.getConnectionHolder().getConnection();

      Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
      txObject.setPreviousIsolationLevel(previousIsolationLevel);
      txObject.setReadOnly(definition.isReadOnly());

      // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
      // so we don't want to do it unnecessarily (for example if we've explicitly
      // configured the connection pool to set it already).
       //2.必须要关闭自动提交设置手动提交,否则你提交代码就提交了事务
      if (con.getAutoCommit()) {
   
         txObject.setMustRestoreAutoCommit(true);
         if (logger.isDebugEnabled()) {
   
            logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
         }
         con.setAutoCommit(false);
      }

      prepareTransactionalConnection(con, definition);
      txObject.getConnectionHolder().setTransactionActive(true);

      int timeout = determineTimeout(definition);
      if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
   
         txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
      }

      // Bind the connection holder to the thread.
       //3.绑定连接
      if (txObject.isNewConnectionHolder()) {
   
         TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
      }
   }

   catch (Throwable ex) {
   
      if (txObject.isNewConnectionHolder()) {
   
         DataSourceUtils.releaseConnection(con, obtainDataSource());
         txObject.setConnectionHolder(null, false);
      }
      throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
   }
}

这里重点的方法都标注出来了,我们一个个看

注释1:给当前事务设置连接,我们之前已经分析了,我们第一次调用testInsert()时,从threadlocal中是没取到ConnectionHolder(其实就是connection的封装),这里就从连接中获取一个connection然后封装成ConnectionHolder设置到事务对象中

注释2:这里就是要跟原生jdbc一样,使用事务,也要先将自动提交设置成手动提交

注释3:这里就比较重要了,其实就是将当前ConnectinoHolder设置到threadlocal中,方便第二个事务调用时能获取到,我们具体看下bindResource()里面的逻辑,还是非常有意思的

4-2-1-1.TransactionSynchronizationManager.bindResource()
public static void bindResource(Object key, Object value) throws IllegalStateException {
   
   Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
   Assert.notNull(value, "Value must not be null");
   Map<Object, Object> map = resources.get();
   // set ThreadLocal Map if none found
   if (map == null) {
   
      map = new HashMap<>();
      resources.set(map);
   }
   Object oldValue = map.put(actualKey, value);
   // Transparently suppress a ResourceHolder that was marked as void...
   if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
   
      oldValue = null;
   }
   if (oldValue != null) {
   
      throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
            actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
   }
   if (logger.isTraceEnabled()) {
   
      logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
            Thread.currentThread().getName() + "]");
   }
}

这个方法就是往threadLocal中设置一个Map<Object,Object>,其中key是数据源,value是ConnectionHolder。这里为什么要用Map而不是直接存储ConnectionHolder呢?因为可能存在多数据源的情况,一个方法如果两个数据源不一样,而我们拿到的连接如果是一样的就有问题了。另外设置到threadlocal中,我们在同一个线程中就能获取到上一次存储的ConnectionHolder了。也就是当我们调用第二个事务方法productService.queryUer()方法时,就能获取到存储在ConnectionHolder了(单个数据源情况下)
//———————————————–强行分页—————————————————————//

到这里我们第一个方法userService.testInsert()的事务已经开启了,我们开始调用业务逻辑,而业务逻辑中又会调用ProductService.queryUser(),这又要进入上述的一样的逻辑了。相同的逻辑我就不继续讲了,我们直接将视野看到代码4中(AbstractPlatformTransactionManager.getTransaction),这里有几个地方需要注意

注释1:这里又创建了一个新的事务,但是事务的连接是从threadlocal中拿的,我们这里没有切换数据源,并且第一次调用UserService.testInsert开始事务时已经往threadlocal中设置了connectionHolder,所以我们这里创建的第二个事务是新的,但是连接和上一个连接是一样的

注释2:这里的if会判断为true,会调用一个非常重要的方法handleExistingTransaction(),下面会详细分析,代码不会走到注释3,因为if里面已经return了。开始看handleExistingTransaction

5.handleExistingTransaction()
private TransactionStatus handleExistingTransaction(
      TransactionDefinition definition, Object transaction, boolean debugEnabled)
      throws TransactionException {
   

    //1.传播属性为PROPAGATION_NEVER
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
   
      throw new IllegalTransactionStateException(
            "Existing transaction found for transaction marked with propagation 'never'");
   }
//2.传播属性为PROPAGATION_NOT_SUPPORTED
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
   
      if (debugEnabled) {
   
         logger.debug("Suspending current transaction");
      }
      Object suspendedResources = suspend(transaction);
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return prepareTransactionStatus(
            definition, null, false, newSynchronization, debugEnabled, suspendedResources);
   }
//3.传播属性为PROPAGATION_REQUIRES_NEW
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
   
      if (debugEnabled) {
   
         logger.debug("Suspending current transaction, creating new transaction with name [" +
               definition.getName() + "]");
      }
      SuspendedResourcesHolder suspendedResources = suspend(transaction);
      try {
   
         return startTransaction(definition, transaction, debugEnabled, suspendedResources);
      }
      catch (RuntimeException | Error beginEx) {
   
         resumeAfterBeginException(transaction, suspendedResources, beginEx);
         throw beginEx;
      }
   }
//4.传播属性为PROPAGATION_NESTED
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
   
      if (!isNestedTransactionAllowed()) {
   
         throw new NestedTransactionNotSupportedException(
               "Transaction manager does not allow nested transactions by default - " +
               "specify 'nestedTransactionAllowed' property with value 'true'");
      }
      if (debugEnabled) {
   
         logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
      }
      if (useSavepointForNestedTransaction()) {
   
         // Create savepoint within existing Spring-managed transaction,
         // through the SavepointManager API implemented by TransactionStatus.
         // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
         DefaultTransactionStatus status =
               prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
         status.createAndHoldSavepoint();
         return status;
      }
      else {
   
         // Nested transaction through nested begin and commit/rollback calls.
         // Usually only for JTA: Spring synchronization might get activated here
         // in case of a pre-existing JTA transaction.
         return startTransaction(definition, transaction, debugEnabled, null);
      }
   }
//5.剩下的几种都走下面的逻辑
   // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
   if (debugEnabled) {
   
      logger.debug("Participating in existing transaction");
   }
   if (isValidateExistingTransaction()) {
   
      if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
   
         Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
         if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
   
            Constants isoConstants = DefaultTransactionDefinition.constants;
            throw new IllegalTransactionStateException("Participating transaction with definition [" +
                  definition + "] specifies isolation level which is incompatible with existing transaction: " +
                  (currentIsolationLevel != null ?
                        isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
                        "(unknown)"));
         }
      }
      if (!definition.isReadOnly()) {
   
         if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
   
            throw new IllegalTransactionStateException("Participating transaction with definition [" +
                  definition + "] is not marked as read-only but existing transaction is");
         }
      }
   }
   boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    //6.要特别注意第三个参数了为newTransaction=false
   return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

代码虽然很长,但是比较容易,无非就是根据上面的几种不同的传播属性,做不同的逻辑。本文重点分析常用的几种传播属性REQUIREDREQUIRES_NEWNESTED,其他的几种也很简单,大家自行分析。

先看REQUIRED,比较见到,看最下面一行就行了

5-1.REQUIRED
//要特别注意第三个参数了为newTransaction=false
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

创建了一个事务状态,但是它的newTransaction=false,也就是它没有资格真正的回滚和提交后面会详细讲

5-2.REQUIRES_NEW

直接看上面的注释3

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
   
   if (debugEnabled) {
   
      logger.debug("Suspending current transaction, creating new transaction with name [" +
            definition.getName() + "]");
   }
    //1.会把上一个事务给挂起
   SuspendedResourcesHolder suspendedResources = suspend(transaction);
   try {
   
       //2.开始事务
      return startTransaction(definition, transaction, debugEnabled, suspendedResources);
   }
   catch (RuntimeException | Error beginEx) {
   
      resumeAfterBeginException(transaction, suspendedResources, beginEx);
      throw beginEx;
   }
}

注释1:将上一个事务挂起,下面会分析

注释2:开始新的事务,这个地方和之前开启事务的逻辑一样,重新设置连接、将连接设置到threadlocal中、将自动提交设置成手动提交

下面我们看下注释1是如何挂起事务的

5-2-1.suspend
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
   
   if (TransactionSynchronizationManager.isSynchronizationActive()) {
   
      List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
      try {
   
         Object suspendedResources = null;
         if (transaction != null) {
   
             //1.重点挂起的逻辑
            suspendedResources = doSuspend(transaction);
         }
         String name = TransactionSynchronizationManager.getCurrentTransactionName();
         TransactionSynchronizationManager.setCurrentTransactionName(null);
         boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
         TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
         Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
         TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
         boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
         TransactionSynchronizationManager.setActualTransactionActive(false);
          //2.返回一个对象,该对象封装了被挂起的事务信息,方便后面能重新拿得到
         return new SuspendedResourcesHolder(
               suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
      }
    //...省
}

接着看注释1的逻辑doSuspend

5-2-1-1.doSuspend
protected Object doSuspend(Object transaction) {
   
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   //将当前事务对象connection设置成null
    txObject.setConnectionHolder(null);
    //解绑,其实就是从threadlocal中删除Map
   return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}

因为创建第二个事务的时候,会将第一个事务的connectionHolder设置进来,这里挂起的操作,就是将第一次设置到threadlocal中的connectionHolder删除掉,并且将当前事务的connection设置成null。然后上面代码5-2.REQUIRES_NEW中的注释2中开启事务startTransaction方法,会将新的connectionHolder设置到threadlocal中,注意,此时startTransaction生成的事务状态的newTransaction=true

5-3.NESTED

接着来看第二个事务是嵌套事务的情况

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
   
   if (!isNestedTransactionAllowed()) {
   
      throw new NestedTransactionNotSupportedException(
            "Transaction manager does not allow nested transactions by default - " +
            "specify 'nestedTransactionAllowed' property with value 'true'");
   }
   if (debugEnabled) {
   
      logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
   }
   if (useSavepointForNestedTransaction()) {
   
      // Create savepoint within existing Spring-managed transaction,
      // through the SavepointManager API implemented by TransactionStatus.
      // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
      //1.创建事务状态
       DefaultTransactionStatus status =
            prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
       //2.创建回滚点
      status.createAndHoldSavepoint();
      return status;
   }
   else {
   
      // Nested transaction through nested begin and commit/rollback calls.
      // Usually only for JTA: Spring synchronization might get activated here
      // in case of a pre-existing JTA transaction.
      return startTransaction(definition, transaction, debugEnabled, null);
   }
}

注释1:创建事务状态,注意此的newTransaction=false

注释2:创建一个回滚点,支持部分回滚,其实就是简单的封装了jdbc,不清楚回滚点的可以自行查阅相关内容

不知不觉已经已经写了很多了,但是这仅仅只是介绍了创建事务的原理,还有事务回滚、事务提交、注意事项都没讲,原本以为一篇文章能全部讲完,但是写太长了怕大家阅读起来比较类有恐惧感,所以我将事务回滚、事务提交、注意事项写在下一篇文章,请移步到(spring源码分析之事务transaction下篇

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/111198.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • SSL连接建立过程分析(1)

    SSL连接建立过程分析(1)

    2021年11月28日
  • 从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

    从K近邻算法、距离度量谈到KD树、SIFT+BBF算法从K近邻算法、距离度量谈到KD树、SIFT+BBF算法前言前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章待写:1、KD树;2、神经网络;3、编程艺术第28章。你看到,blog内的文章与你于别处所见的任何都不同。于是,等啊等,等一台电脑,只好等待..”。得益于田,借了我一台电脑(借他电脑的时候,我连表示感谢,他说“能找到工作全靠你的博客,这点儿小忙还说,不地道”,有的时候,稍许感受到

  • 行列式及其运算和性质[通俗易懂]

    行列式及其运算和性质[通俗易懂]行列式特别注意,行列式虽然表达为一系列数字的数表,但是其本质式一个数,这个跟矩阵有本质的区别.二阶行列式D=∣a11a12a21a22∣=a11a22−a12a21D=\begin{vmatrix}a_{11}&a_{12}\\a_{21}&a_{22}\end{vmatrix}=a_{11}a_{22}-a_{12}a_{21}D=∣∣∣∣​a11​a21​​a12​a22​​∣∣∣∣​=a11​a22​−a12​a21​三阶行列式D=∣a11a12a13a21a2

  • HTML—标签总结

    HTML—标签总结

  • impala中转换字段类型,类型强转

    impala中转换字段类型,类型强转cast(字段名as要转换为的类型)例如:要将student表中的age字段(原本是int类型)转成string类型,如下:cast(student.ageasstring)asage–年龄

  • Nginx和OpenResty专栏帖

    本帖 是用于统计整理Nginx和Openresty相关的学习博客和资料,方便自己学习和后期快速查找对应的知识!Nginx 学习Nginx官網 : http://nginx.org/en/Nginx中文文档 : http://www.nginx.cn/doc/Nginx开发从入门到精通 :http://tengine.taobao.org/book/ 【从模块开发逐渐过渡到nginx原理剖析:比较

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号