搞懂Spring事务机制,一篇文章就够了

前言

本文将从Spring事务的概念说起,理论与实战相结合,彻底搞懂 Spring 事务。

1 事务

1.1 概念

事务是为了达到某个目的而做的一系列操作要么都执行(事务提交),要么都不执行(事务回滚),事务是一组不可分割的操作集合。

1.2 特性

  • 原子性

事务中所有操作都是不可分割的原子单位,所有操作要么全部执行成功,要么全部执行失败。

  • 一致性

事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和不变。

  • 隔离性

是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。

  • 持久性

一旦事务提交成功,事务中所有数据操作都必须持久化到数据库中。

1.3 隔离级别

事务在并发操作中可能会出现以下问题:

  • 脏读

事务A读取了事务B尚未提交的数据,如果事务回滚,则 A 读取使用了错误的数据。

  • 不可重复读

是指在对于数据库中的某个操作,一个事务范围内多次查询却返回不了不同的数据,这是由于在查询间隔,数据被另一个事务修改并提交了,不可重复读指的是数据的更新操作。

  • 幻读

在事务A多次读取过程中,事务B对数据进行了新增操作,导致事务A多次读取的数据不一致,幻读指的是数据的增删操作。

  • 事务丢失

1、A和B同时在操作一个数据,B事务已经提交了,A事务回滚了,这样事务B的操作就因事务A的回滚而回滚了。
2、A和B同时操作一个数据,两个事务同时取到一个数据,事务B首先提交,事务A后提交,这样A的提交就覆盖了B的提交,也称为覆盖丢失。

事务的不同隔离级别可以解决并发事务中出现的几种问题。

  • 未提交读 (read uncommitted)

一个事务可以读取另一个未提交事务的数据。这种隔离级别可以避免事务丢失问题,但可能会出现脏读。

  • 已提交读 (read committed)

一个事务要等到另一个事务提交后才能读取数据,避免了事务丢失和脏读问题,但可能会产生不可重复读。

  • 可重复读 (repeatable read)

在一个事务内,多次读取同一个数据,结果是一致的。也就是在这个事务结束前,其他事务不能访问该数据(包括读写)。避免了不可重复读、脏读、事务丢失问题,但有可能会出现幻读(因为可能会出现新增操作)

  • 串行化 (serializable)

事务的最高隔离级别,事务串行化顺序执行,可以避免脏读、不可重复读、幻读、事务丢失问题。但这种事务隔离级别效率低下,比较消耗数据库性能,一般不使用。

查询 mysql 默认隔离级别
在这里插入图片描述

1.4 传播特性

事务的传播机制一般用在事务嵌套的场景,指的就是当一个事务方法被另一个事务方法调用时,这个事务应该如何执行。常用的事务传播机制如下:

  • PROPAGATION_NEVER:该传播机制不支持外层事务,即如果外层有事务就抛出异常
  • PROPAGATION_NOT_SUPPORTED:该传播机制不支持事务,如果外层存在事务则挂起,执行完内部方法代码,则恢复外层事务,无论是否异常都不会回滚内部方法操作的数据
  • PROPAGATION_SUPPORTS:如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
  • PROPAGATION_REQUIRES_NEW:该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
  • PROPAGATION_NESTED:如果外层方法没有事务,就新建一个事务;如果有,也会新建事务,并且在当前事务中嵌套其他事务
  • PROPAGATION_REQUIRED:Spring默认的事务传播机制,如果外层方法没有事务,就新建一个事务;如果有,就加入外部事务。
  • PROPAGATION_MANDATORY:与 PROPAGATION_NEVER 相反,如果外层方法没有事务,就抛出异常;如果有,就加入外部事务。

1.5 配置方式

1.5.1 编程式事务

编程式事务属于侵入性事务,使用事务管理器 (TransactionManager) 和事务模板 (Spring推荐使用 TransactionTemplate)

1.5.2 声明式事务

声明式事务属于无侵入式事务,管理建立在 AOP 上,本质是对方法进行拦截,在目标方法开始前创建或加入一个事务,执行完目标方法后根据执行的情况进行提交或回滚。

编程式事务每次都要单独实现,但业务量大且功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务属于无侵入式,不会影响业务逻辑的实现;所以,使用声明式事务管理要优于编程式事务管理,这也正是 Spring 倡导的编程方式;不足的是,声明式事务管理的粒度是方法级别,而编程式事务管理的粒度是代码块级别。


2 实战

2.1 PROPAGATION_NEVER 机制

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
    	// 此处注入本类bean,调用此类方法。否则,内部方法不执行事务
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
    throw new RuntimeException("exception");
}

@Transactional(propagation = Propagation.NEVER)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

上述内部方法使用的传播机制为 PROPAGATION_NEVER,而外部方法声明了事务,则会报异常 IllegalTransactionStateException

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

2.2 PROPAGATION_NOT_SUPPORTED 机制

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
    throw new RuntimeException("exception");
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

上述方法使用 PROPAGATION_NOT_SUPPORTED 传播机制,执行程序,会出现死锁。
PROPAGATION_NOT_SUPPORTED 的特点是,如果外层存在事务则挂起,挂起意味着锁表,而两个方法操作的同一个表,由于外部方法会锁表,内部方法获取不到资源,会产生死锁问题。

2.3 PROPAGATION_SUPPORTS 机制

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
}

@Transactional(propagation = Propagation.SUPPORTS)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

使用 PROPAGATION_SUPPORTS 传播机制,执行程序,外部方法和内部方法都回滚了,因为 PROPAGATION_SUPPORTS 机制是完全依赖外层事务,外层有事务,就加入。如果外层没有事务,则按照非事务方式执行,内外部方法都不会发生回滚。

2.4 PROPAGATION_REQUIRES_NEW 机制

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

使用 PROPAGATION_REQUIRES_NEW 传播机制,执行上述程序,也会发生死锁问题,因为会将外层事务挂起。当去掉外层事务时,则会执行内部方法的事务。

2.5 PROPAGATION_NESTED 机制

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
}

@Transactional(propagation = Propagation.NESTED)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

使用 PROPAGATION_NESTED 传播机制,上述程序中,内部方法中有异常,外部方法没有异常,此时执行,内部方法会新建事务,内部方法中操作会回滚,而外部方法中不会回滚;此时,将内部方法中异常去掉,异常放到外部方法中执行,内外部方法都会回滚。因为是嵌套事务,外部事务出现异常,内部事务也会回滚。

2.6 PROPAGATION_REQUIRED 机制

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
}

@Transactional(propagation = Propagation.REQUIRED)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

使用 PROPAGATION_REQUIRED 传播机制(Spring默认事务传播机制),内部方法有异常,外部方法没异常,执行程序,因为外部方法有事务,所以内部方法使用的外部事务,两个方法共用一个事务,当其中一个方法有异常时两个方法都会回滚。

2.7 PROPAGATION_MANDATORY 机制

@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    try {
        userController.rollback();
    } catch (RuntimeException e) {
        e.printStackTrace();
    }
    throw new RuntimeException("exception");
}

@Transactional(propagation = Propagation.MANDATORY)
public void rollback() {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

使用 PROPAGATION_MANDATORY 传播机制,与 PROPAGATION_NEVER 机制相反,外部方法中不添加事务,会报下列异常。

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

如果外部方法中添加了事务,则内部方法使用外部事务。也就是不管外部方法还是内部方法有异常,两个都会回滚。


3 PROPAGATION_REQUIRED 机制详解

由于 Spring中默认事务传播机制就是 PROPAGATION_REQUIRED ,在这详细介绍 PROPAGATION_REQUIRED 机制。

3.1 默认回滚机制

3.1.1 demo1
@Transactional
@PutMapping("/update")
public void updateUser() throws SQLException {
    userMapper.updateUserInfo();
    throw new SQLException("exception");
}

上述事务会回滚吗?

经验证,不会回滚,Spring 的默认事务只回滚 RuntimeException 和 Error

3.2 指定回滚异常

3.2.1 demo1
@Transactional(rollbackFor = {SQLException.class})
@PutMapping("/update")
public void updateUser() throws SQLException {
    userMapper.updateUserInfo();
    throw new SQLException("exception");
}

上述事务会回滚吗?

会回滚。如果要指定哪些异常需要回滚,则使用 @Transactional 的 rollbackFor 属性显式指定

3.2.2 demo2
@Transactional(rollbackFor = {SQLException.class})
@PutMapping("/update")
public void updateUser() throws RuntimeException {
    userMapper.updateUserInfo();
    throw new RuntimeException("exception");
}

显式指定的回滚异常是 SQLException ,实际抛出异常是 RuntimeException,这种情况会回滚吗?

会回滚,此时,上述程序遇到 RuntimeException ,Error ,SQLException 都会回滚。

3.3 嵌套事务

3.3.1 demo1
@Transactional
public void rollback() throws RuntimeException {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

@Transactional
@PutMapping("/update")
public void updateUser() {
    userMapper.insertUserInfo();    // A
    rollback();
}

上述事务会回滚吗?哪个操作(A , B)会被提交?

经验证,A B 两个操作都不会被提交,内部外部事务都发生了回滚。因为捕捉到的异常都在 @Transactional 能处理的范围内。

3.3.2 demo2
@Transactional
public void rollback() {
    userMapper.updateUserInfo();    // B
}

@Transactional
@PutMapping("/update")
public void updateUser() throws SQLException {
    userMapper.insertUserInfo();    // A
    rollback();
    throw new SQLException("exception");
}

外部方法中抛出了未指定的且默认不回滚的异常,内部事务未抛出异常,此时,事务会回滚吗?哪个操作(A , B)会被提交?

上述实例中,外部事务中由于抛出 SQLException ,不再默认事务的捕捉范围内,所以不会被回滚,由于两个方法共用的一个事务,内部事务中的操作也不会被回滚。反之,内部事务中抛出 SQLException ,外部事务中没有异常,则二者的操作也都不会被回滚。总之,内外部方法共用一个事务时,如果其中一方有可以捕捉的异常,都会被回滚,否则,都不回滚。

3.3.3 demo3
@Transactional
public void rollback() throws RuntimeException {
    userMapper.updateUserInfo();    // B
    throw new RuntimeException("exception");
}

@Transactional
@PutMapping("/update")
public void updateUser() throws SQLException {
    userMapper.insertUserInfo();    // A
    rollback();
    throw new SQLException("exception");
}

上述实例中,外部方法抛出了 SQLException(当前事务无法捕捉的异常),而内部方法抛出了 RuntimeException(当前事务可以捕捉的异常),此时,二者会被回滚还是被提交?

经验证,上述实例中两个方法都会被回滚,因为程序先遇到的异常是 RuntimeException ,是可以捕捉的异常,所以此时就会发生内外两个方法的回滚操作。如果外部方法中抛出 RuntimeException ,内部方法中抛出 SQLException,则二者都不回滚,因为程序遇到的第一个异常是 SQLException,是当前事务不可捕捉的,所以二者都 不会被回滚。


4 Spring 事务核心类/接口介绍

PlatformTransactionManager

在这里插入图片描述

Spring 的 PlatformTransactionManager 接口继承自 TransactionManager ,是事务管理的顶层接口,其中包括三个方法:

  • TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
  • void commit(TransactionStatus status) throws TransactionException;
  • void rollback(TransactionStatus status) throws TransactionException;

PlatformTransactionManager 的一个抽象实现类 AbstractPlatformTransactionManager,这个类实现了事务管理的整个逻辑关系流程,但是把和具体事务打交道的又定义为抽象方法,让子类去实现。

事务处理的核心方法 invokeWithinTransaction() 中就调用了 PlatformTransactionManager 的三个方法。

对于单个数据库事务的具体实现类就是 DataSourceTransactionManager,此类会完成这些和事务相关的具体操作,它适用的场景是:“mybatis”,“jdbctemplate”,“本地事务”。


TransactionStatus

TransactionStatus 是一个表示事务状态的接口,继承了 SavepointManager,代表 TransactionStatus 接口提供了返回此事务是否带保存点的方法,即是否创建为基于保存点的嵌套事务。还提供了将底层会话刷新到数据存储区的方法。

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
	// 是否带有保存点
	boolean hasSavepoint();
	
	// 将底层会话刷新到数据存储区
	@Override
	void flush();
}


5 Spring 事务原理

众所周知,Spring 事务采用 AOP 实现,事务的实现机制可以总结为以下几个步骤,接下来将从源码的角度分析 Spring 是如何实现事务管理的。

5.1 宏观认识

我们从事务基类 TransactionAspectSupport 的 invokeWithinTransaction() 方法说起。

在这里插入图片描述

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {
	
	// 获取 @Transactional 注解的属性源
	TransactionAttributeSource tas = getTransactionAttributeSource();
	// 获取 @Transactional 注解属性
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	// 获取事务管理器,事务管理器共有两种实现,分别是: PlatformTransactionManager 和 ReactiveTransactionManager
	final TransactionManager tm = determineTransactionManager(txAttr);
	
	// 如果获取的事务管理器是ReactiveTransactionManager
	if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
		......
	}
	// 获取 PlatformTransactionManager 事务管理器
	PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
	// 获取连接点识别,即事务的方法名称
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
	
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// 创建事务
		TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
	
		Object retVal;
		try {
			// 环绕增强,调用链中的下一个拦截器(职责链模式)
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// 回滚事务
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			// 清理当前线程的事务相关信息
			cleanupTransactionInfo(txInfo);
		}
		......
		// 提交事务
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}
	......
}

5.2 创建事务

在这里插入图片描述

进入 createTransactionIfNecessary() 方法

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
	@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
	
	// 确定事务名称(默认方法名称)
	if (txAttr != null && txAttr.getName() == null) {
		......
	}
	
	TransactionStatus status = null;
	if (txAttr != null) {
		if (tm != null) {
			// 获取事务状态
			status = tm.getTransaction(txAttr);
		}
		else {
			......
		}
	}
	return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

进入到 getTransaction(txAttr); 获取事务状态

@Override
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、如果存在事务
	if (isExistingTransaction(transaction)) {
		// 为现有事务创建 TransactionStatus
		return handleExistingTransaction(def, transaction, debugEnabled);
	}
	
	......

	// 检查事务传播行为
	// 当前事务为PROPAGATION_MANDATORY机制抛出异常(没有外部事务就抛异常)
	if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		......
	}
	// 当前事务为PROPAGATION_REQUIRED || PROPAGATION_REQUIRES_NEW || PROPAGATION_NESTED 时
	else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
			def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
		// 挂起外部事务(参数为null,因为此时没有外部事务)
		SuspendedResourcesHolder suspendedResources = suspend(null);
		try {
			// 创建 TransactionStatus 对象
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			DefaultTransactionStatus status = newTransactionStatus(
					def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
			// 根据指定的事务定义开启新事物
			doBegin(transaction, def);
			// 事务同步准备
			prepareSynchronization(status, def);
			return status;
		}
		......
	}
	else {
		......
	}
}

进入到 DataSourceTransactionManager 的 doBegin(transaction, def) ,当外部方法没有事务时,开启新事物
在这里插入图片描述

@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();

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

		// 关闭自动提交
		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);
		// 如果 timeout 属性不是默认值,设置此属性
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		// 线程绑定此连接
		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);
	}
}

进入到 AbstractPlatformTransactionManager 的 handleExistingTransaction(),当存在外部事务时,为事务创建 transactionStatus 对象

private TransactionStatus handleExistingTransaction(
	TransactionDefinition definition, Object transaction, boolean debugEnabled)
		throws TransactionException {
	// 如果事务传播机制为 PROPAGATION_NEVER 抛异常
	if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
		throw new IllegalTransactionStateException(
				"Existing transaction found for transaction marked with propagation 'never'");
	}
	// 如果事务传播机制为 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);
		// 创建 TransactionStatus
		return prepareTransactionStatus(
				definition, null, false, newSynchronization, debugEnabled, suspendedResources);
	}
	// 如果事务传播机制为 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 {
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			// 新建 TransactionStatus
			DefaultTransactionStatus status = newTransactionStatus(
					definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
			// 新建事务
			doBegin(transaction, definition);
			// 事务同步准备
			prepareSynchronization(status, definition);
			return status;
		}
		catch (RuntimeException | Error beginEx) {
			// 内部事务异常时恢复外部事务
			resumeAfterBeginException(transaction, suspendedResources, beginEx);
			throw beginEx;
		}
	}
	// 	如果事务传播机制为 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()) {
			DefaultTransactionStatus status =
					prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
			// 设置事务保存点
			status.createAndHoldSavepoint();
			return status;
		}
		else {
			// 通过嵌套的 begin 和 commit/rollback 调用嵌套事务
			boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
			DefaultTransactionStatus status = newTransactionStatus(
					definition, transaction, true, newSynchronization, debugEnabled, null);
			doBegin(transaction, definition);
			prepareSynchronization(status, definition);
			return status;
		}
	}

	// 如果事务传播机制为: 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);
	// 新建 TransactionStatus
	return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

我们看看 Spring 是如何挂起事务的?进入到 AbstractPlatformTransactionManager 的 suspend()

@Nullable
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);
			// 新建挂起资源持有者对象
			return new SuspendedResourcesHolder(
					suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
		}
		catch (RuntimeException | Error ex) {
			// 挂起事务失败,恢复事务状态
			doResumeSynchronization(suspendedSynchronizations);
			throw ex;
		}
	}
	else if (transaction != null) {
		// 事务没有同步激活
		Object suspendedResources = doSuspend(transaction);
		return new SuspendedResourcesHolder(suspendedResources);
	}
	else {
		// Neither transaction nor synchronization active.
		return null;
	}
}

5.3 回滚事务

进入到 TransactionAspectSupport 的 completeTransactionAfterThrowing()

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
	// 判断事务信息和事务状态
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
		if (logger.isTraceEnabled()) {
			logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
					"] after exception: " + ex);
		}
		// 事务属性信息不为null && 回滚异常
		if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
			try {
				// 回滚事务状态
				txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
			}
			//.....catch
		}
		else {
			// 不回滚异常,提交事务状态
			try {
				txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
			}
			//.....catch
		}
	}
}

来到实际处理回滚事务的方法 processRollback()

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
	boolean unexpectedRollback = unexpected;
	try {
		// 回滚前触发
		triggerBeforeCompletion(status);
		// 如果存在保存点,回滚到保留的保存点
		if (status.hasSavepoint()) {
			if (status.isDebug()) {
				logger.debug("Rolling back transaction to savepoint");
			}
			status.rollbackToHeldSavepoint();
		}
		// 如果存在新事务,回滚
		else if (status.isNewTransaction()) {
			if (status.isDebug()) {
				logger.debug("Initiating transaction rollback");
			}
			doRollback(status);
		}
		else {
			// 如果有外层事务
			if (status.hasTransaction()) {
				// 仅本地回滚 || 失败的全局回滚
				if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
					if (status.isDebug()) {
						logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
					}
					// 仅设置给定的事务回滚
					doSetRollbackOnly(status);
				}
			}
			// 全局回滚时是否提前失败,设置意外回滚标识
			if (!isFailEarlyOnGlobalRollbackOnly()) {
				unexpectedRollback = false;
			}
		}
	}
	catch (RuntimeException | Error ex) {
		triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
		throw ex;
	}
	// 回滚后触发
	triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
finally {
	// 完成后清理
	cleanupAfterCompletion(status);
}

5.4 提交事务

回到 TransactionAspectSupport 的 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());
	}
}

进入到实际处理事务提交的方法,AbstractPlatformTransactionManager 的 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()) {
				if (status.isDebug()) {
					logger.debug("Releasing transaction savepoint");
				}
				unexpectedRollback = status.isGlobalRollbackOnly();
				status.releaseHeldSavepoint();
			}
			// 如有新事物就提交事务
			else if (status.isNewTransaction()) {
				if (status.isDebug()) {
					logger.debug("Initiating transaction commit");
				}
				unexpectedRollback = status.isGlobalRollbackOnly();
				doCommit(status);
			}
			else if (isFailEarlyOnGlobalRollbackOnly()) {
				unexpectedRollback = status.isGlobalRollbackOnly();
			}
		}
		// ...... catch 
		try {
			// 提交后触发
			triggerAfterCommit(status);
		}
		finally {
			// 完成后触发
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
		}
	}
	finally {
		// 完成后清理
		cleanupAfterCompletion(status);
	}
}

总结

Spring事务的整体处理流程为,创建事务管理器 —> 创建事务 —> 如有异常的情况就回滚 —> 清理当前线程的事务相关信息 —> 最后提交事务

评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值