一文讲透Spring事务原理

162 阅读14分钟

大家好,这篇文章将带领大家深入了解 Spring 事务实现机制。

在开始之前,我们需要注意区分 Spring 中物理事务逻辑事务的区别:

  • 物理事务:对应数据库实际执行的事务操作。物理事务需要通过 JDBC connection 开启、提交/回滚;
  • 逻辑事务:从业务逻辑角度划分的事务单元。根据业务的需求,将一组 SQL 看成一个整体。在 Spring 中,一个事务单元可以理解成一个带有@Transactional的方法;

试想一下,如果有多个“逻辑事务”相互嵌套,该如何处理呢?是共用一个“物理事务”,还是单独再开启一个事务,又或者是其他操作?

这就是 Spring 事务传播行为所决定的事情,简单来说,Spring 事务传播行为就是用来解决多个逻辑事务物理事务之间的对应关系问题的,除此之外,Spring 还提供了诸如事务扩展、声明式事务等这些简易的使用方式。

1. Spring 事务抽象

1.1. 核心组件简介

Spring 事务涉及到的核心组件

  • PlatformTransactionManager接口: Spring 事务管理的核心接口,定义了事务获取提交回滚三个最基础能力;
  • TransactionDefinition 接口:用于定义事务(隔离级别、传播行为、超时、只读、回滚规则);
  • TransactionStatus 接口:表示事务的状态,存储事务状态信息;

1.2. PlatformTransactionManager —— 事务管理器

Spring 通过事务管理器(PlatformTransactionManager)管理事务,接口定义如下:

public interface PlatformTransactionManager extends TransactionManager {
   // 获取事务,会根据事务传播行为返回"事务状态"
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;
   // 提交事务
	void commit(TransactionStatus status) throws TransactionException;
   // 回滚事务
	void rollback(TransactionStatus status) throws TransactionException;
}

这是一个策略接口,不同的平台可以有不同的实现,比如 JDBC 的实现为 DataSourceTransactionManager、Hibernate 中的实现为 HibernateTransactionManager、JPA 的实现为 JpaTransactionManager、Reidisson 的实现为 RedissonTransactionManager 等等;

Spring 提供了一个基础实现类 AbstractPlatformTransactionManager,这是一个模板类,封装了事务标准工作流程, 具体细节由子类实现;DataSourceTransactionManager、HibernateTransactionManager、JpaTransactionManager 等都继承了此抽象类;

1.3. TransactionDefinition —— 事务定义

根据上一节的内容,PlatformTransactionManager#getTransaction(...) 方法用于开启事务,并返回事务状态;其入参为TransactionDefinition实例,用于描述一个事务,接口定义如下:

public interface TransactionDefinition {
   // 事务传播行为常量
	int PROPAGATION_REQUIRED = 0;
	int PROPAGATION_SUPPORTS = 1;
	int PROPAGATION_MANDATORY = 2;
	int PROPAGATION_REQUIRES_NEW = 3;
	int PROPAGATION_NOT_SUPPORTED = 4;
	int PROPAGATION_NEVER = 5;
	int PROPAGATION_NESTED = 6;

   // 事务隔离级别常量
	int ISOLATION_DEFAULT = -1;
	int ISOLATION_READ_UNCOMMITTED = 1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
	int ISOLATION_READ_COMMITTED = 2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
	int ISOLATION_REPEATABLE_READ = 4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
	int ISOLATION_SERIALIZABLE = 8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;

	int TIMEOUT_DEFAULT = -1;

	default int getPropagationBehavior() {
		return PROPAGATION_REQUIRED;
	}

	default int getIsolationLevel() {
		return ISOLATION_DEFAULT;
	}

	default int getTimeout() {
		return TIMEOUT_DEFAULT;
	}

	default boolean isReadOnly() {
		return false;
	}

	@Nullable
	default String getName() {
		return null;
	}

   // 获取默认事务定义
	static TransactionDefinition withDefaults() {
		return StaticTransactionDefinition.INSTANCE;
	}
}

接口中定义了一些常量和 getter 方法,用于获取事务属性:传播行为、隔离级别、超时时间、是否只读、事务名称;

1.4. TransactionStatus —— 事务状态

TransactionStatus 表示一个事务的状态,可以用来获取事务信息手动回滚事务(不用抛异常);继承自TransactionExecution 和 SavepointManager 接口,接口定义如下:

public interface TransactionExecution {
    // 是否是新事务
	boolean isNewTransaction();
    // 设置事务为"只能回滚"状态, 即手动回滚事务
	void setRollbackOnly();
	boolean isRollbackOnly();
    // 事务是否已完成
	boolean isCompleted();
}

// Savepoint相关操作,目前工作中没用到过
public interface SavepointManager {
	Object createSavepoint() throws TransactionException;
	void rollbackToSavepoint(Object savepoint) throws TransactionException;
	void releaseSavepoint(Object savepoint) throws TransactionException;
}

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
    // 事务有没有Savapoint (JDBC才有,似乎不常用? 反正我没用到过)
	boolean hasSavepoint();
	@Override
	void flush();
}

总结一句话:TransactionStatus 封装了一个事务的具体信息,可以用来手动回滚事务。

如果你用过 TransactionTemplate 编程式事务:transactionTemplate.execute(status -> {xxxxxx}); 这里的status就是 TransactionStatus。

2. Spring 事务核心流程

Spring 事务通过模板方法模式定义了事务的工作流程,具体的事务管理器实现类只需要实现相关回调方法即可接入 Spring 事务。

2.1. 获取 / 开启事务——getTransaction(...)

在抽象类AbstractPlatformTransactionManager 中,getTransaction是个一个模板方法定义了标准的事务工作流程

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

    // ...
    
    @Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {
           // 1. 模板方法,获取当前事务对象(Object类型,因为子类实现各不相同)
		Object transaction = doGetTransaction();

		if (isExistingTransaction(transaction)) {
			// 2. 当前线程已经存在事务,按照事务传播行为处理
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// 3. 当前线程不存在事务
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
                 // 3.1 传播行为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 {
                          // 3.2 开启事务
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
                  // 3.3 不使用事务
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}
}

doGetTransaction(...)返回的是一个事务对象,内部封装了数据库连接等信息,其返回类型为什么是 Object

  • 事务对象在子类中的实现是不同的,父类不需要实际操作这个对象,用 Object 类型接收单纯起到一个引用的作用;
  • 父类在调用doBegin(...) doRollBack(...) doResume(...) doSuspend(...) doCleanupAfterCompletion(...)这些模板方法时,会将doGetTransaction(...)返回的transaction实例再次传给子类,子类根据自己的具体实现进行强转;

getTransaction整体流程是比较容易理解的,先获取当前线程事务信息,根据当前线程是否存在事务,产生 2 个分支逻辑:

  • case 1: 当前线程存在事务,按照用户指定的事务传播行为进行处理,返回事务状态;
  • case 2: 当前线程不存在事务,按照事务传播行为决定是否开始事务;
    • case 2.1. MANDATORY:抛异常;(不常用)
    • case 2.2. REQUIREDREQUIRES_NEWNESTED:开启新事务;
    • case 2.3. 其余情况,不使用事务;(不常用)

先来介绍一下比较简单的 case 2.2 开启新事务,这个逻辑比较简单,只需调用子类doBegin新创建一个事务实例,将事务信息封装进 TransactionStatus:

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
		boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
	  boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 1. 实例化"事务状态",封装事务相关参数
    DefaultTransactionStatus status = newTransactionStatus(
			definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    // 2. 调用模板方法,开启事务
    doBegin(transaction, definition);
    // 3. 将事务信息绑定到当前线程 ThradLocal
    prepareSynchronization(status, definition);
    // 4. 返回事务状态
    return status;
}

说明: TransactionStatus 封装了当前事务的状态信息,如数据库连接、是否新事务、是否开启事务同步、挂起的事务资源等。

回到 case 1 当前线程存在事务,这种情况有些麻烦了,Spring 会按照当前事务单元的事务传播行为进行处理,先来简单回顾下 Spring 事务传播行为:

  • REQUIRED:如果存在一个事务,则加入当前事务;否则新创建一个事务;
  • SUPPORTS:如果存在一个事务,则加入当前事务;否则按照非事务的方式执行;
  • MANDATORY:如果存在一个事务,则加入当前事务;否则抛出异常;
  • REQUIRES_NEW:总是创建一个新的事务;如果已经存在一个事务,则将其挂起;
  • NOT_SUPPORTED:不支持事务;如果存在一个事务,则挂起此事务,自己以非事务的方式执行;
  • NEVER:永远不支持事务;如果存在一个事务,则抛出异常;
  • NESTED:如果存在事务,则运行在一个嵌套的事务中;如果没有活动的事务则按照REQUIRED执行;

相关源码如下,按照 TransactionDefinition 中的传播行为分别处理:

private TransactionStatus handleExistingTransaction(
		TransactionDefinition definition, Object transaction, boolean debugEnabled)
		throws TransactionException {
  // 传播行为=NEVER  -> 抛异常
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
		throw new IllegalTransactionStateException(
				"Existing transaction found for transaction marked with propagation 'never'");
	}
  // 传播行为=NOT_SUPPORTED  -> 挂起当前事务,返回事务状态
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
		Object suspendedResources = suspend(transaction);
		boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(
				definition, null, false, newSynchronization, debugEnabled, suspendedResources);
	}
  // 传播行为=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;
		}
	}
  // 传播行为=NESTED -> 当前事务平台是否支持savepoint,支持则使用savepoint
	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 (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 {
                   // 不使用savepoint,直接开启新事物
			return startTransaction(definition, transaction, debugEnabled, null);
		}
	}
	// 传播行为=PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED
	if (isValidateExistingTransaction()) { // 是否校验现存事务和此事务
        // 校验两个事务定义是否兼容
        // 略...
	}
    //PROPAGATION_SUPPORTS、 PROPAGATION_REQUIRED 都是加入当前事务,所以新创建一个事务状态即可
	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

2.1.1. 事务挂起(suspend)与恢复(resume)

事务挂起(suspend)恢复(resume) 用于处理事务嵌套的问题。

举个例子:在一个事务中,当子方法需要执行独立事务时,就会将当前事务挂起,从TransactionSynchronizationManager中暂时移除当前事务的状态,将当前事务状态封装进SuspendedResourcesHolder,放入新事务的 TransactionStatus 中;子方法独立事务执行完毕之后,再拿出挂起的事务,重新绑定至TransactionSynchronizationManager

简言之,事务挂起就是将线程 ThreadLocal 中的事务状态暂时清空;而 resume 则是将事务状态恢复,重新设置到 ThreadLocal 中。

挂起 (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);
			}
                  // 重置事务同步管理器中线程的状态
			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);
			// 把当前事务的各种状态封装进 SuspendedResourcesHolder
                  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;
	}
}

恢复 (resume) 操作是挂起的逆操作,源码如下:

protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
		throws TransactionException {
    
	if (resourcesHolder != null) {
          // 1. 获取被挂起的资源
		Object suspendedResources = resourcesHolder.suspendedResources;
		if (suspendedResources != null) {
                  // 2. 调用子类恢复方法(子类一般是恢复数据库连接信息)
			doResume(transaction, suspendedResources);
		}
           // 3. 恢复事务状态,将事务属性重新绑定至当前线程
		List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
		if (suspendedSynchronizations != null) {
			TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
			TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
			TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
			TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
			doResumeSynchronization(suspendedSynchronizations);
		}
	}
}

以上,便是 Spring 获取事务的大体流程。可以发现,抽象类对事务传播行为处理逻辑进行了封装,子类无需再去关心如何处理事务传播,只需实现父类给出的模板方法即可(doGetTransaction()doBegin(...)等),父类会在合适的时机对子类方法进行调用,这就是模板方法模式的精髓所在。

2.2. 回滚事务 —— rollback

因为在 commit 的逻辑中涉及到了回滚,所以先来看看事务回滚的逻辑:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

    // ...
    @Override
    public final void rollback(TransactionStatus status) throws TransactionException {
		if (status.isCompleted()) {
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		processRollback(defStatus, false);
	}

    private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
                  // true-回滚完抛异常  false-不抛异常
			boolean unexpectedRollback = unexpected;

			try {
                          // 1. 触发TransactionSynchronization#beforeCompletion回调
				triggerBeforeCompletion(status);
                          // 2.1 如果有savapoint,回滚到savepoint
				if (status.hasSavepoint()) {
					status.rollbackToHeldSavepoint();
				}
                          // 2.2 如果是新事务 -> 调用模板方法 回滚事务
				else if (status.isNewTransaction()) {
					doRollback(status);
				}
                          // 2.3 当前是子事务,只设置回滚状态,让外层事务回滚
				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) {
                          // 3.1 异常情况下,触发afterCompletion回调
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw ex;
			}
                  // 3.2 无异常情况下,触发afterCompletion回调
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

			// Raise UnexpectedRollbackException if we had a global rollback-only marker
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
		}
		finally {
                   // 4. 清理事务状态,主要是清理跟线程绑定的状态
                   // 注:如果是子事务,会在这里恢复被挂起的事务
			cleanupAfterCompletion(status);
		}
	}
    
    // ...
}

processRollback是按照“事务状态”进行回滚操作的:

  • 如果有 savepoint,就回滚到上一个 savepoint(这个 case 应该不太常用,了解即可,反正我在工作中没用到过这个~);
  • 如果是“新事务”,调用子类方法doRollback进行回滚;
    • “新事务”是啥意思?“嵌套事务”的最外层事务是新事务,内部事务不是新事务。比如, A 和 B 方法都有 @Transactional注解,A 调用了 B,那么 A 中的 status.isNewTransaction()为 true,B 中的status.isNewTransaction()为 false;
  • 如果不是“新事务”,即当前事务是“嵌套事务”的内部事务 status,此时设置“只能回滚状态”即可,让外层事务执行真正回滚操作;

2.3. 提交事务——commit

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {

    // ...
    
    @Override
	public final void commit(TransactionStatus status) throws TransactionException {
		if (status.isCompleted()) { // 事务已经完成 非法状态 -> 抛异常
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
          // 1. 当前事务状态被设置了"只能回滚" -> 回滚事务
		if (defStatus.isLocalRollbackOnly()) { 
			processRollback(defStatus, false);
			return;
		}
          // 2. defStatus.isGlobalRollbackOnly()为true 说明内层事务需要回滚,外层也要跟着回滚
	 	if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			processRollback(defStatus, true); // 这种情况下会抛出 UnexpectedRollbackException 异常
			return;
		}
          // 3. 正常提交事务
		processCommit(defStatus);
	}

    // ...
    
}

processCommit的逻辑类似processRollback,这里就不粘贴代码了。我们重点看一下commit中的回滚逻辑:

  • 第一种情况,如果当前 status 被设置了 rollbackOnly=true,就执行回滚逻辑;
  • 第二种情况,稍有些复杂:
    • shouldCommitOnGlobalRollbackOnly表示回滚的时候要不要执行 commit 逻辑,绝大部分情况都是 false,所以可以忽略这个条件;
    • defStatus.isGlobalRollbackOnly()为 true: 如果存在嵌套事务,内层事务通过status.setRollbackOnly()方式回滚事务(没抛异常),此时外层事务也要跟着回滚;(不理解可以先看看 2.2 中status.isNewTransaction()=fasle的情况)

3. Spring 声明式事务原理

Spring 声明式事务涉及到的组件如下:

  • AnnotationTransactionAttributeSource:用于解析@Transactional注解中的属性;
  • TransactionInterceptor:事务切面逻辑;
  • BeanFactoryTransactionAttributeSourceAdvisor:用于匹配 @Transactional 注解,为所在 bean 创建代理;

对于声明式事务,其基本原理是 AOP,具体切面逻辑如下:

public class TransactionInterceptor extends TransactionAspectSupport 
        implements MethodInterceptor, Serializable {

	@Override
	public Object invoke(final 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 InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}

}

invokeWithinTransaction方法的代码就不放了,其大致流程如下:

总结:声明式事务最终也是通过PlatformTransactionManager进行事务管理的,只不过在此之前多了一步解析 @Transactional注解的流程。

4. Spring 编程式事务原理

4.1. 基本用法

可以通过 TransactionTemplate 实现编程式事务,基本用法如下:

    @Resource
    private TransactionTemplate transactionTemplate;
    
    public void testTransaction() {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 执行业务代码
                } catch (Exception e){
                    // 将事务设置为仅可回滚状态,可以用来代替抛异常触发回滚
                    status.setRollbackOnly();
                }
            }
        });
    }

4.2. 实现原理

编程式事务相对更加好理解一些,TransactionTemplate 相关源码如下:

public class TransactionTemplate extends DefaultTransactionDefinition
		implements TransactionOperations, InitializingBean {

	@Nullable
	private PlatformTransactionManager transactionManager;
        
  // ...

	@Override
	@Nullable
	public <T> T execute(TransactionCallback<T> action) throws TransactionException {
		Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

		if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
			return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
		}
		else {
                  // 1. 开启事务
			TransactionStatus status = this.transactionManager.getTransaction(this);
			T result;
			try {
                          // 2. 执行业务逻辑
				result = action.doInTransaction(status);
			}
			catch (RuntimeException | Error ex) {
				// 业务抛出异常,回滚
				rollbackOnException(status, ex);
				throw ex;
			}
			catch (Throwable ex) {
				// 业务抛出异常,回滚
				rollbackOnException(status, ex);
				throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
			}
                  // 无异常,提交事务
			this.transactionManager.commit(status);
			return result;
		}
	}

    // ...
}

上述代码很容易理解,就是流水账式的代码:通过事务管理器开启事务、执行业务逻辑、提交或回滚事务;

5. 总结

本文首先介绍了 Spring 事务的核心组件:PlatformTransactionManager、TransactionDefinition 和TransactionStatus。

然后重点分析了事务管理器模板类 AbstractPlatformTransactionManager获取事务、回滚、提交事务的逻辑,Spring 在模板方法中已经帮我们处理了事务传播行为、嵌套事务等复杂的操作,具体的事务管理器只需实现模板类提供的回调方法即可接入 Spring 事务。

最后,我们简单的分析了一下 Spring 声明式事务编程式事务的工作流程,它们都是依靠 Spring 的事务管理器PlatformTransactionManager完成事务获取、提交或回滚的;