前言
本文将从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事务的整体处理流程为,创建事务管理器 —> 创建事务 —> 如有异常的情况就回滚 —> 清理当前线程的事务相关信息 —> 最后提交事务