JDBC与Spring事务及事务传播性原理解析-下篇

上篇,在看这篇的时候,推荐先查看上篇。上篇我们主要介绍了JDBC的一些基本操作,以及Spring事务传播的一些概念,主要是从JDBC的角度来说的,这篇我们从Spring的角度来梳理下事务及其传播的使用以及源码的处理流程。

一、Spring不同事务传播demo

1、一些前置知识点说明

1)、Datasource

​ 我们在前面的demo中获取Connection是名称直接通过DriverManager.getConnection创建的,但对于这个JDBC也有抽象一个接口也就是Datasource

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLer05ZF-1668333065095)(F:\MarkDown-File\知识点资料\JDBC与Spring事务及事务传播性原理解析.assets\image-20221113100132934.png)]

​ 同时通过这个Datasource,我们更常见的是线程池,例如Spring默认使用的线程池实现HikariDataSource

public static void main(String[] args) throws SQLException, ClassNotFoundException {
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test");
    config.setUsername("root");
    config.setPassword("xxx");
    config.setDriverClassName("com.mysql.cj.jdbc.Driver");
    DataSource dataSource = new HikariDataSource(config);
    Connection connection = dataSource.getConnection();
    int insert = jdbcUtils.insert(connection);
    System.out.println("-----insert ---- " + insert);
    int i = delete(connection);
    System.out.println("--------delete ------" + i );
}

2)、事务的传播性

​ 我们上面说过,Spring事务的传播性是对我们demo的几种操作的抽象及具体的实现,下面我们就以PROPAGATION_REQUIRE_NEW来说明下

PROPAGATION_REQUIRE_NEW	若当前没有事务,则新建一个事务。若当前存在事务,则新建 一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交

​ 上面关于这个定义,我们从代码中来说:

​ 若当前存在事务,则新建 一个事务,新老事务相互独立。我们可以将其理解为,如果调用当前方法的上面的方法已经有了事务(已经有了一个Connectiom),我们就需要再新建一个事务来处理当前方法(获取一个新Connection来操作当前方法,同时也需要上一个事务的信息进行挂起,也就是暂时保存,例如上一个Connection,由于同时会有很多线程操作,所以这里一般会用到ThreadLocal),也就是到时如果当前方法发生异常需要回滚的话,就回滚当前方法的sql,而不影响其他调用当前方法的上面的方法的执行(这里其实与PROPAGATION_NESTED,有点类似,但他们两个不是一个概念,因为PROPAGATION_NESTED用到是同一个Connection,而这里用的是两个Connnection)。

2、Spring的事务demo

1)、Propagation.REQUIRES_NEW与Propagation.NEVER

@Transactional(propagation = Propagation.REQUIRED)
public void studentOrderAdd()
{
    //  Propagation.REQUIRES_NEW
    studentService.add();
    //  Propagation.NEVER
    insOrderService.add();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void add()
{
    Student student = new Student();
    student.setAge((byte) 30);
    student.setName("瑞环"+Math.random());
    studentMapper.insert(student);
}
@Transactional(propagation = Propagation.NEVER)
public int add()
{
    InsOrder insOrder = new InsOrder();
    insOrder.setName("订单"+Math.random());
    insOrder.setAge((int) Math.random()*100);
    return insOrderMapper.insert(insOrder);
}

​ 可以看到目前我们这个demo,在最外面我们是设置的Propagation.REQUIRED,也就是需要事务,如果没有就会建一个事务。然后对于studentService.add()我们设置的是Propagation.REQUIRES_NEW,也就是会新建一个事务,与studentOrderAdd的事务是分开的,互不影响。然后对于insOrderService.add()方法,我们设置的是Propagation.NEVER,也就是不需要事务,当它的上面由于studentOrderAdd()是已经创建了,所以其就会不执行。然后对于这个整体来说,我们就可以知道,最后Student会插入成功,然后Order就不会执行

JDBC与Spring事务及事务传播性原理解析-下篇_第1张图片

2)、Propagation.REQUIRED与Propagation.NEVER

下面我们改一下demo,也就是将studentService.add(),改为Propagation.REQUIRED,也就是它会与上面发放用一个事务。

@Transactional(propagation = Propagation.REQUIRED)
public void studentOrderAdd()
{
    //  Propagation.REQUIRED
    studentService.add();
    //  Propagation.NEVER
    insOrderService.add();
}

JDBC与Spring事务及事务传播性原理解析-下篇_第2张图片

​ 可以看到这次我们两张表都没有数据。

JDBC与Spring事务及事务传播性原理解析-下篇_第3张图片

​ 上面我们是通过简单demo说明了下不同事务传播机制的区别,要具体了解几种事务传播的操作可以搜索其他博文,这方面的博文应该有很多。

三、Spring事务传播源码解析

​ 下面我们就来具体分析下Spring事务相关的源码

1、invokeWithinTransaction

JDBC与Spring事务及事务传播性原理解析-下篇_第4张图片

​ 关于事务的入口逻辑是在TransactionInterceptor中处理。首先是通过方法获取其的事务描述,例如事务的传播类型、隔离级别:

JDBC与Spring事务及事务传播性原理解析-下篇_第5张图片

​ 然后再获取其的事务管理器,因为我们的事务注解@Transactional是能指定对应的事务管理器的。

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();
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   final TransactionManager tm = determineTransactionManager(txAttr);
		//编程式事务、先不管
   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.
      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.
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         // target invocation exception
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         cleanupTransactionInfo(txInfo);
      }
   	............
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }
   else {
      	..............
   }
}

​ 这里就是Spring事务的核心处理逻辑了,获取到事务处理后,然后再获取到当期线程的事务信息TransactionInfo,再执行业务方法,通过invocation.proceedWithInvocation();,当执行业务方法失败的话,就通过completeTransactionAfterThrowing方法,不然的话,就通过commitTransactionAfterReturning,进行提交。

2、createTransactionIfNecessary

protected static final class TransactionInfo {

   @Nullable
   private final PlatformTransactionManager transactionManager;

   @Nullable
   private final TransactionAttribute transactionAttribute;

   private final String joinpointIdentification;

   @Nullable
   private TransactionStatus transactionStatus;

   @Nullable
   private TransactionInfo oldTransactionInfo;

​ 我们可以其有oldTransactionInfo,也就是当前事务方法的前面的事务方法,然后其他的transactionManagertransactionStatus是当前事务的信息记录。

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) {
         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(txAttr) 初始化创建、获取当前事务状态。

1)、getTransaction方法

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

   // Use defaults if no transaction definition given.
   TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

   Object transaction = doGetTransaction();
   boolean debugEnabled = logger.isDebugEnabled();

   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());
   }
		........
}
@Override
protected Object doGetTransaction() {
   DataSourceTransactionObject txObject = new DataSourceTransactionObject();
   txObject.setSavepointAllowed(isNestedTransactionAllowed());
   ConnectionHolder conHolder =
         (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
   txObject.setConnectionHolder(conHolder, false);
   return txObject;
}

​ 这里就是获取当前事务状态信息,对于doGetTransaction()方法,获取DataSourceTransactionObject,也就是当前的ConnectionHolder,也就是JDBC中的Connection获取当前线程的Connection。如果获取不到,也就是当前线程还没有事务,conHolder就会为空。

public class ConnectionHolder extends ResourceHolderSupport {

   @Nullable
   private ConnectionHandle connectionHandle;

   @Nullable
   private Connection currentConnection;

    public ConnectionHolder(ConnectionHandle connectionHandle) {
		Assert.notNull(connectionHandle, "ConnectionHandle must not be null");
		this.connectionHandle = connectionHandle;
	}
private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");
.............
private static Object doGetResource(Object actualKey) {
   Map<Object, Object> map = resources.get();
   if (map == null) {
      return null;
   }
   Object value = map.get(actualKey);
	........
   return value;
}

​ 获取到这个后,再是通过isExistingTransaction(transaction),判断当前线程是不是已经有了事务。

@Override
protected boolean isExistingTransaction(Object transaction) {
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}

​ 这个方法主要就是的判断依据就是ConnectionHolder,看ConnectionHolder有没有,以及是否被激活

public boolean hasConnectionHolder() {
   return (this.connectionHolder != null);
}

​ 如果有并被激活,我们的代码逻辑就是走的return handleExistingTransaction(def, transaction, debugEnabled);处理。

​ 如果还没有事务,就是对几种不同传播机制进行处理:

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);
   try {
      return startTransaction(def, transaction, debugEnabled, suspendedResources);
   }
   catch (RuntimeException | Error ex) {
      resume(null, suspendedResources);
      throw ex;
   }
}

   boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
   return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}

​ 如果是PROPAGATION_MANDATORY,也就是当前事务方法一定也运行在已经有事务的环境下,不然就抛出异常No existing transaction found for transaction marked with propagation 'mandatory'

​ 而另外的几种TransactionDefinition.PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEWPROPAGATION_NESTED,其都是自己本身如果不满足要求,能自己直接创建事务。我们可以看到如果走的是这个逻辑分支,然后会调用suspend方法,这个方法主要是挂起当前线程中本身已存在的事务信息。当我们注意。

2)、suspend方法

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
   if (TransactionSynchronizationManager.isSynchronizationActive()) {
      List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
      try {
         Object suspendedResources = null;
         if (transaction != null) {
            suspendedResources = doSuspend(transaction);
         }
          //下面主要是将当前线程的事务描叙内容设置为null,也就是还没有激活状态
         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);
         return new SuspendedResourcesHolder(
               suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
      }
      catch (RuntimeException | Error ex) {
         // doSuspend failed - original transaction is still active...
         doResumeSynchronization(suspendedSynchronizations);
         throw ex;
      }
   }
   else if (transaction != null) {
      // Transaction active but no synchronization active.
      Object suspendedResources = doSuspend(transaction);
      return new SuspendedResourcesHolder(suspendedResources);
   }
   else {
      // Neither transaction nor synchronization active.
      return null;
   }
}

​ 但我们注意,我们目前还没有事务,也就是TransactionSynchronizationManager.isSynchronizationActive()transaction != null都是不满足的,所以我们这里返回的是null。同时这个方法的主要是doSuspendSynchronization(),这个主要是获取到当前线程已经存在的事务描叙信息,例如当前事务方法前面事务方法的描述。同时在调用suspend是,如果已经有事务,其会通过doSuspend(transaction),来处理挂起逻辑:

protected Object doSuspend(Object transaction) {
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   txObject.setConnectionHolder(null);
   return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}

​ 也就是将线程已经持有的ConnectionHolder,设置为null,同时将绑定在当前线程的连接信息下掉(从ThreadLocal移除),这样的话,后面需要事务的话,就再通过Datasource新获取一个Connection来操作当前方法的事务。

private static Object doUnbindResource(Object actualKey) {
   Map<Object, Object> map = resources.get();
   if (map == null) {
      return null;
   }
   Object value = map.remove(actualKey);
   	.........
   return value;
}

​ 然后再是正式通过doBegin,来初始化当前事务方法的各种信息。

3)、startTransaction方法

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

   boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
   DefaultTransactionStatus status = newTransactionStatus(
         definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
   doBegin(transaction, definition);
   prepareSynchronization(status, definition);
   return status;
}

4)、doBegin方法

@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   Connection con = null;

   try {
      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();
		.................
       txObject.getConnectionHolder().setTransactionActive(true);
		............

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

   catch (Throwable ex) {
    .........   }
}

​ 这里首先是判断当前有没有Connection,没有就通过数据源创建一个Connection newCon = obtainDataSource().getConnection(); 。然后再通过TransactionSynchronizationManager.bindResource,将当前事务方法的ConnectionHolder绑定到resources线程上下文中。

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);
   ........
}

​ 上面是如果我们还没有事务的处理,下面我们回到前面看下有事务的处理,也就是handleExistingTransaction的逻辑。

5)、handleExistingTransaction方法

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

   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
      throw new IllegalTransactionStateException(
            "Existing transaction found for transaction marked with propagation 'never'");
   }

   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
      Object suspendedResources = suspend(transaction);
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return prepareTransactionStatus(
            definition, null, false, newSynchronization, debugEnabled, suspendedResources);
   }

   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
     
      SuspendedResourcesHolder suspendedResources = suspend(transaction);
      try {
         return startTransaction(definition, transaction, debugEnabled, suspendedResources);
      }
      catch (RuntimeException | Error beginEx) {
         resumeAfterBeginException(transaction, suspendedResources, beginEx);
         throw beginEx;
      }
   }

   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      if (debugEnabled) {
         logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
      }
      if (useSavepointForNestedTransaction()) {
         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);
      }
   }
  	............
   }
   boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
   return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

​ 首先是PROPAGATION_NEVER,也就是不需要事务,如果有的话,抛出异常Existing transaction found for transaction marked with propagation 'never'

​ 然后是PROPAGATION_NOT_SUPPORTED,也就是不在事务中执行,Object suspendedResources = suspend(transaction);,可以看到这里首先会将线程已经有的事务挂起。

​ 而如果是PROPAGATION_REQUIRES_NEW,其也会调suspend(transaction)挂起当前线程的事务,但这里会再通过startTransaction来新开一个事务。也就是在startTransaction方法调用doBegin方法时,会再获取一次Connection,这个可以再去看``。但这里我们注意,这里与第一次开启,也就是当前线程还没有事务不同的是SuspendedResourcesHolder也就是当前线程已存在的事务是有内容的,这个信息是用来当前方法事务处理完后,恢复线程以前事务用的。

​ 再之后是TransactionDefinition.PROPAGATION_NESTED,这个会用到保存点,也就是status.createAndHoldSavepoint()

,其不会新获取Connection

public void createAndHoldSavepoint() throws TransactionException {
   setSavepoint(getSavepointManager().createSavepoint());
}

我们了解这些后,再回到最前面的invokeWithinTransaction方法,来处理回滚、或提交的内容。

3、completeTransactionAfterThrowing

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
   if (txInfo != null && txInfo.getTransactionStatus() != null) {
      if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
         try {
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
         }
         catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
         }
         catch (RuntimeException | Error ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            throw ex2;
         }
      }
      else {
         // We don't roll back on this exception.
         // Will still roll back if TransactionStatus.isRollbackOnly() is true.
         try {
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
         }
         catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
         }
         catch (RuntimeException | Error ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            throw ex2;
         }
      }
   }
}

​ 这里有两个,一个是回滚,当是我们指定的异常时,就回滚(可以通过@Transactional指定只发生指定的异常才回滚),不然就提交。

1)、processRollback

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
   try {
      boolean unexpectedRollback = unexpected;

      try {
         triggerBeforeCompletion(status);

         if (status.hasSavepoint()) {
            status.rollbackToHeldSavepoint();
         }
         else if (status.isNewTransaction()) {
            doRollback(status);
         }
         else {
            // Participating in larger transaction
            if (status.hasTransaction()) {
               if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                  doSetRollbackOnly(status);
               }
            }
            // Unexpected rollback only matters here if we're asked to fail early
            if (!isFailEarlyOnGlobalRollbackOnly()) {
               unexpectedRollback = false;
            }
         }
      }
      catch (RuntimeException | Error ex) {
         triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
         throw ex;
      }
		............
   }
   finally {
      cleanupAfterCompletion(status);
   }
}

​ 回滚主要两种,一种就是保存点,另一直是整个事务回滚

public void rollbackToHeldSavepoint() throws TransactionException {
   Object savepoint = getSavepoint();
   if (savepoint == null) {
      throw new TransactionUsageException(
            "Cannot roll back to savepoint - no savepoint associated with current transaction");
   }
   getSavepointManager().rollbackToSavepoint(savepoint);
   getSavepointManager().releaseSavepoint(savepoint);
   setSavepoint(null);
}
protected void doRollback(DefaultTransactionStatus status) {
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
   Connection con = txObject.getConnectionHolder().getConnection();
   if (status.isDebug()) {
      logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
   }
   try {
      con.rollback();
   }
   catch (SQLException ex) {
      throw translateException("JDBC rollback", ex);
   }
}

4、commitTransactionAfterReturning

​ 另一个就是我们业务方法没有问题,正常执行,就会通过commitTransactionAfterReturning方法来提交事务。

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
   if (txInfo != null && txInfo.getTransactionStatus() != null) {
      if (logger.isTraceEnabled()) {
         logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
      }
      txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
   }
}

1)、processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
   try {
      boolean beforeCompletionInvoked = false;

      try {
         boolean unexpectedRollback = false;
         prepareForCommit(status);
         triggerBeforeCommit(status);
         triggerBeforeCompletion(status);
         beforeCompletionInvoked = true;
         if (status.hasSavepoint()) {
            unexpectedRollback = status.isGlobalRollbackOnly();
            status.releaseHeldSavepoint();
         }
         else if (status.isNewTransaction()) {
            unexpectedRollback = status.isGlobalRollbackOnly();
            doCommit(status);
         }
         else if (isFailEarlyOnGlobalRollbackOnly()) {
            unexpectedRollback = status.isGlobalRollbackOnly();
         }

      }
      	.........
      // Trigger afterCommit callbacks, with an exception thrown there
      // propagated to callers but the transaction still considered as committed.
      try {
         triggerAfterCommit(status);
      }
      finally {
         triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
      }
   }
   finally {
      cleanupAfterCompletion(status);
   }
}

同时在这里我们要注意,不管是回滚、还是提交,其最后都会调用cleanupAfterCompletion方法,这个方法是我们前面提到的,用来恢复当前线程的事务环境的,也就是当前方法的事务处理完了,获取前面方法的事务环境。

2)、cleanupAfterCompletion

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
   status.setCompleted();
   if (status.isNewSynchronization()) {
      TransactionSynchronizationManager.clear();
   }
   if (status.isNewTransaction()) {
      doCleanupAfterCompletion(status.getTransaction());
   }
   if (status.getSuspendedResources() != null) {
      if (status.isDebug()) {
         logger.debug("Resuming suspended transaction after completion of inner transaction");
      }
      Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
      resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
   }
}

​ 这里主要3个逻辑,如果是新的同步信息,清理同步上下文。

public static void clear() {
   synchronizations.remove();
   currentTransactionName.remove();
   currentTransactionReadOnly.remove();
   currentTransactionIsolationLevel.remove();
   actualTransactionActive.remove();
}

​ 如果是新事务,释放当前连接:

protected void doCleanupAfterCompletion(Object transaction) {
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

   // Remove the connection holder from the thread, if exposed.
   if (txObject.isNewConnectionHolder()) {
      TransactionSynchronizationManager.unbindResource(obtainDataSource());
   }

   // Reset connection.
   Connection con = txObject.getConnectionHolder().getConnection();
   try {
      if (txObject.isMustRestoreAutoCommit()) {
         con.setAutoCommit(true);
      }
      DataSourceUtils.resetConnectionAfterTransaction(
            con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
   }
   catch (Throwable ex) {
      logger.debug("Could not reset JDBC Connection after transaction", ex);
   }

   if (txObject.isNewConnectionHolder()) {
     
      DataSourceUtils.releaseConnection(con, this.dataSource);
   }

   txObject.getConnectionHolder().clear();
}

​ 最后是主要逻辑,也就是我们前面强调的SuspendedResources信息,resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources())方法的调用。

​ 我们修改我们前面demo:

@Transactional(propagation = Propagation.REQUIRED)
public void add()
{
    //  Propagation.REQUIRED
    studentService.add();
    //  Propagation.REQUIRES_NEW
    insOrderService.add();
}

​ 将其改为这种组合,看其执行完insOrderService.add()后,SuspendedResources的值。

JDBC与Spring事务及事务传播性原理解析-下篇_第6张图片

​ 我们可以看到,上一个事务相关的信息,也就是com.fev.spring.boot.demo.service.StudentOrderService.add,它与当前方法事务用的Connection是不同的。然后这里就会通过resume方法来恢复

protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
      throws TransactionException {

   if (resourcesHolder != null) {
      Object suspendedResources = resourcesHolder.suspendedResources;
      if (suspendedResources != null) {
         doResume(transaction, suspendedResources);
      }
      List suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
      if (suspendedSynchronizations != null) {
         TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
         TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
         TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
         TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
         doResumeSynchronization(suspendedSynchronizations);
      }
   }
}
public abstract class TransactionSynchronizationManager {

   private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

   private static final ThreadLocal<Map<Object, Object>> resources =
         new NamedThreadLocal<>("Transactional resources");

   private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
         new NamedThreadLocal<>("Transaction synchronizations");

   private static final ThreadLocal<String> currentTransactionName =
         new NamedThreadLocal<>("Current transaction name");

   private static final ThreadLocal<Boolean> currentTransactionReadOnly =
         new NamedThreadLocal<>("Current transaction read-only status");

   private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
         new NamedThreadLocal<>("Current transaction isolation level");

   private static final ThreadLocal<Boolean> actualTransactionActive =
         new NamedThreadLocal<>("Actual transaction active");

​ 可以看到会将上一个事务的信息,设置到线程上下文中。再是doResumeSynchronization方法执行,获取上一个Connection的信息。

3)、doResumeSynchronization

private void doResumeSynchronization(List<TransactionSynchronization> suspendedSynchronizations) {
   TransactionSynchronizationManager.initSynchronization();
   for (TransactionSynchronization synchronization : suspendedSynchronizations) {
      synchronization.resume();
      TransactionSynchronizationManager.registerSynchronization(synchronization);
   }
}
public void resume() {
  if (this.holderActive) {
    LOGGER.debug(() -> "Transaction synchronization resuming SqlSession [" + this.holder.getSqlSession() + "]");
    TransactionSynchronizationManager.bindResource(this.sessionFactory, this.holder);
  }
}

​ 重新绑定前面的holder到当前线程中。

​ 上面我们大体梳理了下Spring事务以及传播机制相关的源码流程。其核心就是通过在线程中使用ThreadLocal对Connection的获取、挂起、恢复的组装来实现不同的传播效果。

你可能感兴趣的:(mysql,#,Spring系列,spring,java,mysql)