第3篇-事务传播机制源码深度解析
约 2398 字大约 8 分钟
2026-05-24
四、handleExistingTransaction():处理"当前有事务"的情况
如果当前已经有事务了,getTransaction() 会调用 handleExistingTransaction() 方法。
这个方法会根据传播行为,决定是加入当前事务、挂起当前事务并新建一个、还是抛异常。
// 类路径:org.springframework.transaction.support.AbstractPlatformTransactionManager
public abstract class AbstractPlatformTransactionManager
implements PlatformTransactionManager, Serializable {
/**
* 【核心方法】:处理当前已经有事务的情况。
*
* 这个方法会根据传播行为,决定是加入当前事务、
* 挂起当前事务并新建一个、还是抛异常。
*
* @param definition 事务定义
* @param transaction 当前事务对象
* @param debugEnabled 是否启用 debug 日志
* @return 事务状态(TransactionStatus)
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 1. PROPAGATION_NEVER:当前有事务,抛异常!
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 2. PROPAGATION_NOT_SUPPORTED:当前有事务,挂起它!
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 【核心】:挂起当前事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 返回一个新的 TransactionStatus,但没有实际事务(挂起的事务不算)
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 3. PROPAGATION_REQUIRES_NEW:当前有事务,挂起它,并新建一个!
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 【核心】:挂起当前事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 【核心】:开启新事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
// 如果开启事务失败,恢复挂起的资源
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 4. PROPAGATION_NESTED:当前有事务,创建嵌套事务!
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 4.1 检查是否允许嵌套事务
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() + "]");
}
// 4.2 如果支持保存点(JDBC 3.0+),就创建保存点
if (useSavepointForNestedTransaction()) {
// 【核心】:创建保存点(Savepoint)
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint(); // 创建保存点
return status;
}
// 4.3 如果不支持保存点,就创建新事务(比如 JTA)
else {
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// 5. PROPAGATION_SUPPORTS 或 PROPAGATION_REQUIRED:加入当前事务!
// (也就是:什么都不做,直接使用当前事务)
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
// 5.1 如果设置了 validateExistingTransaction = true,会校验隔离级别和只读属性
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);
// 【核心】:加入当前事务(什么都不做,直接返回)
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
}关键发现:
PROPAGATION_REQUIRED和PROPAGATION_SUPPORTS都会加入当前事务:- 区别是:
REQUIRED在当前没有事务时会新建,SUPPORTS不会 - 但如果当前有事务,它们的行为是一样的:加入当前事务
- 区别是:
PROPAGATION_REQUIRES_NEW会挂起当前事务,并新建一个:- 挂起的事务会被保存在
SuspendedResourcesHolder中 - 新事务提交或回滚后,会恢复挂起的事务
- 挂起的事务会被保存在
PROPAGATION_NESTED会创建嵌套事务:- 如果支持保存点(JDBC 3.0+),就创建保存点
- 嵌套事务回滚时,只会回滚到保存点,不会影响外层事务
- 但外层事务回滚时,会回滚所有嵌套事务
五、suspend() 和 resume():事务的挂起与恢复
5.1 suspend():挂起事务
// 类路径:org.springframework.transaction.support.AbstractPlatformTransactionManager
public abstract class AbstractPlatformTransactionManager
implements PlatformTransactionManager, Serializable {
/**
* 【核心方法】:挂起事务。
*
* 这个方法会:
* 1. 挂起事务同步资源(TransactionSynchronization)
* 2. 调用 doSuspend() 挂起实际的事务(子类实现)
* 3. 保存挂起的状态(隔离级别、只读属性等)
*
* @param transaction 当前事务对象
* @return 挂起的资源(SuspendedResourcesHolder)
*/
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// 1. 如果当前有事务同步资源
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 1.1 挂起事务同步资源
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
// 1.2 挂起实际的事务(子类实现)
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
// 1.3 保存当前事务的状态
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);
// 1.4 返回挂起的资源(包含挂起的状态)
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// 如果挂起失败,恢复事务同步资源
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
// 2. 如果当前没有事务同步资源,但有事务对象
else if (transaction != null) {
// 2.1 挂起实际的事务(子类实现)
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
// 3. 如果当前既没有事务同步资源,也没有事务对象
else {
// 什么都不做,返回 null
return null;
}
}
}5.2 resume():恢复事务
// 类路径:org.springframework.transaction.support.AbstractPlatformTransactionManager
public abstract class AbstractPlatformTransactionManager
implements PlatformTransactionManager, Serializable {
/**
* 【核心方法】:恢复事务。
*
* 这个方法会:
* 1. 恢复事务同步资源(TransactionSynchronization)
* 2. 调用 doResume() 恢复实际的事务(子类实现)
* 3. 恢复挂起的状态(隔离级别、只读属性等)
*
* @param transaction 当前事务对象(可能为 null)
* @param resources 挂起的资源(SuspendedResourcesHolder)
*/
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resources)
throws TransactionException {
// 1. 如果有挂起的资源
if (resources != null) {
// 1.1 恢复事务同步资源
Object suspendedResources = resources.getSuspendedResources();
if (resources.hasSuspendedSynchronizations()) {
List<TransactionSynchronization> suspendedSynchronizations =
resources.getSuspendedSynchronizations();
// 恢复当前事务的状态
TransactionSynchronizationManager.setActualTransactionActive(resources.wasActive());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resources.getIsolationLevel());
TransactionSynchronizationManager.setCurrentTransactionReadOnly(resources.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(resources.getName());
// 恢复事务同步资源
doResumeSynchronization(suspendedSynchronizations);
}
// 1.2 恢复实际的事务(子类实现)
if (suspendedResources != null) {
doResume(transaction, suspendedResources);
}
}
}
}关键发现:
suspend()会保存当前事务的所有状态:- 事务名称
- 只读属性
- 隔离级别
- 事务是否活跃
- 事务同步资源
- 实际的事务资源(连接等)
resume()会恢复这些状态:- 这样,被挂起的事务就能继续运行了
六、嵌套事务的实现(保存点)
PROPAGATION_NESTED 会创建嵌套事务。
嵌套事务的实现,依赖于数据库的保存点(Savepoint) 机制。
6.1 什么是保存点?
保存点是 JDBC 3.0 引入的特性。它允许你在一个事务中创建"子事务":
外层事务 BEGIN
↓
INSERT INTO users ... (外层事务的操作)
↓
SAVEPOINT sp1 (创建保存点)
↓
INSERT INTO orders ... (嵌套事务的操作)
↓
ROLLBACK TO sp1 (回滚到保存点,只回滚嵌套事务的操作)
↓
INSERT INTO logs ... (外层事务继续)
↓
COMMIT (提交外层事务,包括后续的操作)关键点:
- 嵌套事务回滚时,只会回滚到保存点,不会影响外层事务
- 但外层事务回滚时,会回滚所有嵌套事务
6.2 Spring 中保存点的实现
// 类路径:org.springframework.transaction.support.DefaultTransactionStatus
public class DefaultTransactionStatus extends DefaultTransactionDefinition {
/**
* 【核心方法】:创建并持有保存点。
*
* 这个方法会调用 Connection.savepoint() 创建保存点。
*/
public void createAndHoldSavepoint() throws TransactionException {
setSavepointManager(getSavepointManager());
getSavepointManager().createSavepoint();
}
}
// 类路径:org.springframework.jdbc.datasource.DataSourceTransactionManager
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
/**
* 【核心方法】:创建保存点。
*
* 这个方法会调用 Connection.savepoint() 创建保存点。
*/
@Override
protected SavepointManager createSavepointManager() {
return new SavepointManager() {
@Override
public Object createSavepoint() throws TransactionException {
// 【核心】:调用 Connection.savepoint() 创建保存点
Connection con = getConnection();
return con.savepoint();
}
@Override
public void rollbackToSavepoint(Object savepoint) throws TransactionException {
// 【核心】:调用 Connection.rollback(savepoint) 回滚到保存点
Connection con = getConnection();
con.rollback((java.sql.Savepoint) savepoint);
}
@Override
public void releaseSavepoint(Object savepoint) throws TransactionException {
// 【核心】:调用 Connection.releaseSavepoint(savepoint) 释放保存点
Connection con = getConnection();
con.releaseSavepoint((java.sql.Savepoint) savepoint);
}
};
}
}七、扩展点总结
在这篇文章中,我们提到了以下几个扩展点:
| 扩展点 | 场景 | 如何扩展 |
|---|---|---|
| 自定义传播行为 | 你想实现自己的传播行为 | 继承 AbstractPlatformTransactionManager,重写 handleExistingTransaction() 方法 |
| 自定义嵌套事务实现 | 你想用其他方式实现嵌套事务(比如,用独立的事务) | 重写 useSavepointForNestedTransaction() 方法,返回 false |
| 严格校验已有事务 | 你想让隔离级别、只读属性等必须一致 | 设置 validateExistingTransaction = true |
| 自定义挂起/恢复逻辑 | 你想在挂起/恢复时做一些额外操作 | 重写 doSuspend() 和 doResume() 方法 |
八、小结与伏笔
好了,到这里,我们已经把事务传播机制的"神秘面纱"揭开了。
让我们来回顾一下整个流程:
- 当调用一个事务方法时,
TransactionInterceptor.invoke()会被调用 invoke()方法调用了TransactionAspectSupport.invokeWithinTransaction()方法invokeWithinTransaction()方法调用了createTransactionIfNecessary()方法createTransactionIfNecessary()方法调用了getTransaction()方法getTransaction()方法会根据传播行为,决定是新建事务、加入当前事务、还是以非事务方式执行- 如果当前有事务,
getTransaction()会调用handleExistingTransaction()方法 handleExistingTransaction()方法会根据传播行为,决定是加入当前事务、挂起当前事务并新建一个、还是抛异常
🔮 伏笔:事务是如何"拿到"连接的?
你可能会注意到,getTransaction() 方法会调用 doBegin() 方法开启事务。
而 doBegin() 方法会从数据源获取连接!
那么问题来了:
- 事务管理器是如何从数据源获取连接的?
- 连接是如何被"绑定"到当前线程的?
- 连接是如何被"挂起"和"恢复"的?
这些问题,我们会在下一篇文章(系列一第4篇:事务隔离级别的实现原理)中继续讲解。
下一篇预告:《Spring 事务(四):事务隔离级别的实现原理》
在这篇文章中,我们会讲解:
- SQL 标准的 4 种隔离级别
- Spring 如何在
doBegin()中设置隔离级别 - 隔离级别与锁的关系(MVCC / Next-Key Lock)
- 不同隔离级别下,"脏读 / 不可重复读 / 幻读"的发生条件
写在最后:这篇文章比较长,但我觉得值得。因为只有当理解了事务传播机制的原理,你才能真正理解 Spring 事务的工作原理。如果你有什么疑问,欢迎留言讨论!