文章目录
- 前言
- 10.5 声明式事务的传播行为控制
- 10.5.1 修改测试代码
- (1)新建一个Service类,并引用UserService
- (2)修改主启动类
- 10.5.2 PROPAGATION_REQUIRED
- 10.5.2.1 tm.getTransaction
- (1)获取事务
- (2)当前已有事务时的传播行为处理
- (3)超时检测
- (4)当前事务不存在时的传播行为处理
- (5)开启新事务:```startTransaction```
- 10.5.2.2 prepareTransactionInfo
- 10.5.2.3 UserServie.test
- 10.5.2.4 handleExistingTransaction
- (1)传播行为PROPAGATION_NEVER的处理
- (2)传播行为PROPAGATION_NOT_SUPPORTED的处理
- (3)传播行为PROPAGATION_REQUIRES_NEW的处理
- (4)传播行为PROPAGATION_NESTED的处理
- (5)传播行为PROPAGATION_REQUIRED和PROPAGATION_SUPPORTS的处理
- 10.5.3 PROPAGATION_REQUIRES_NEW
- 10.5.3.1 挂起原事务:```suspend```
- 10.5.3.2 开启新事务:```startTransaction```
- 10.5.3.3 内层新事务执行完成后的处理
- 10.6 小结
前言
在实际项目开发中,难免遇到Service之间的相互嵌套。如何控制这些嵌套Service的事务,则涉及到SpringFramework的事务传播行为。
10.5 声明式事务的传播行为控制
事务传播行为指的是外层事务传播到内层事务后,内层事务做出的行为。
SpringFramework通过事务传播行为可以控制一个Service中的事务传播到另一个Service方法中的方式。SpringFramework在TransactionDefinition类中定义了7种传播行为:
源码1:TransactionDefinition.java
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;
这7种传播行为的含义分别是:
- PROPAGATION_REQUIRED:必需的。如果当前没有事务运行,则会开启一个新的事务;如果当前已有事务运行,则方法会运行在当前事务中。
- PROPAGATION_SUPPORTS:支持。如果当前没有事务运行,则方法也不会运行在事务中;如果当前已有事务运行,则方法也会运行在当前事务中。
- PROPAGATION_MANDATORY:强制。当前方法必须运行在事务中,如果没有事务则抛出异常。
- PROPAGATION_REQUIRES_NEW:新事务。如果当前没有事务运行,则会开启一个新的事务;如果当前已有事务运行,则会将该事务挂起(暂停),重新开启一个事务。当新的事务运行完毕后,释放原来的事务。
- PROPAGATION_NOT_SUPPORTED:不支持。如果当前没有事务运行,则方法也不运行在事务中;如果当前已有事务运行,则会将该事务挂起(暂停)。
- PROPAGATION_NEVER:不允许。当前方法不允许运行在事务中,如果有事务则抛出异常。
- PROPAGATION_NESTED:嵌套。如果当前没有事务运行,则会开启一个新的事务;如果当前已有事务运行,则会记录一个保存点,方法继续运行在当前事务中。如果方法出现异常,则不会全部回滚,而是回滚到上一个保存点。
简单总结如下:
REQUIRED | SUPPORTS | MANDATORY | REQUIRES_NEW | NOT_SUPPORTED | NEVER | NESTED | |
---|---|---|---|---|---|---|---|
已有事务运行 | 运行当前事务 | 运行当前事务 | 运行当前事务 | 挂起原事务,开启新事务;新事务运行完后释放原事务 | 挂起原事务,然后不运行事务 | 抛出异常 | 记录保存点,继续运行当前事务,如果出现异常则回滚到保存点 |
没有事务运行 | 开启新事务 | 不运行事务 | 抛出异常 | 开启新事务 | 不运行事务 | 不运行事务 | 开启新事务 |
10.5.1 修改测试代码
(1)新建一个Service类,并引用UserService
@Service
public class DeptService {
@Autowired
private UserService userService;
@Transactional(rollbackFor = Exception.class)
public void save() {
System.out.println("DeptService.save 执行了...");
userService.test();
}
}
通过引用UserService,实现Service的嵌套。
(2)修改主启动类
@SpringBootApplication
@EnableTransactionManagement
public class JDBCApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(JDBCApp.class, args);
DeptService deptService = context.getBean(DeptService.class);
deptService.save();
}
}
10.5.2 PROPAGATION_REQUIRED
默认情况下,标注@Transactional注解对应的事务传播行为是PROPAGATION_REQUIRED,这种传播行为的特征是执行Service方法时必定确保事务的开启。
创建事务的位置是TransactionAspectSupport类的invokeWithinTransaction
方法。
源码2:TransactionAspectSupport.java
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// ......
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
//......
} // else ......
}
源码3:TransactionAspectSupport.java
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 如果事务定义中没有指定name,则将方法名作为事务定义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 {
// logger ...
}
}
// 构建事务信息
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
由 源码3 可知,createTransactionIfNecessary
方法有两个核心动作:根据事务定义信息获取事务状态,以及获取事务状态后事务信息构建。
10.5.2.1 tm.getTransaction
事务管理器的getTransaction
方法定义在DataSourceTransactionManager的父类AbstractPlatformTransactionManager中。这个方法的篇幅很长,下面拆解来看。
(1)获取事务
源码4:AbstractPlatformTransactionManager.java
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// 如果没有给定事务定义信息,则使用默认的
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// (1)获取事务
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// ......
}
由 源码4 可知,getTransaction
方法首先会转调do开头的doGetTransaction
方法获取事务。该方法本身是一个模板方法,它的实现定义在DataSourceTransactionManager中。
源码5:DataSourceTransactionManager.java
protected Object doGetTransaction() {
// 创建DataSourceTransactionObject对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 组合ConnectionHolder对象
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
由 源码5 可知,doGetTransaction
方法会创建并返回一个DataSourceTransactionObject对象,该对象内部包含了一个ConnectionHolder,而ConnectionHolder内部又组合了一个Connection对象。
换句话说,doGetTransaction
方法执行后,返回了一个Connection对象。
(2)当前已有事务时的传播行为处理
源码6:AbstractPlatformTransactionManager.java
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// (1)获取事务 ...
// (2)当前已有事务时的传播行为处理
if (isExistingTransaction(transaction)) {
return handleExistingTransaction(def, transaction, debugEnabled);
}
// ......
}
由于在执行DeptService的save
方法之前,当前线程还没有开启事务,因此该if判断的结果为false,不会进入handleExistingTransaction
方法。
(3)超时检测
源码7:AbstractPlatformTransactionManager.java
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// (1)获取事务 ...
// (2)当前已有事务时的传播行为处理 ...
// (3)超时检测
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// ......
}
由 源码7 可知,接着的if结构进行超时校验,实际上就是校验@Transactional注解中的timeout属性。
SpringFramework支持的事务模型可以显式设置事务方法最长执行时间(@Transactional注解中的timeout属性),当方法的执行时间超过该时间,则会抛出异常。
默认情况下,timeout属性的值为-1,表示不限制事务方法的执行时间。这里的if结构判断显式设置的timeout属性值小于-1时,说明值本身设置不合理,抛出异常。
(4)当前事务不存在时的传播行为处理
源码8:AbstractPlatformTransactionManager.java
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// (1)获取事务 ...
// (2)外部事务已存在时的逻辑
// (3)超时检测
// (4)当前事务不存在时的传播行为处理
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
// 传播行为:PROPAGATION_MANDATORY
// 强制要求方法运行在事务中,由于此时线程中没有事务,因此抛出异常
// throw ...
} else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 传播行为:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
// 如果当前线程中没有事务,则开启一个新的事务
SuspendedResourcesHolder suspendedResources = suspend(null);
// logger ...
try {
// 开启一个新的事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
} // catch ...
} else {
// 剩余的传播行为:PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER
// 如果当前线程没有事务,则方法也不运行在事务中
// logger ...
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
由 源码8 可知,getTransaction
方法的第4部分逻辑是当前事务不存在时的传播行为处理。程序进入该部分源码,说明当前线程中没有开启事务,事实上也是如此,源码根据事务定义中配置的事务传播行为分别了做了不同处理。
- 传播行为是PROPAGATION_MANDATORY时,强制要求方法运行在事务中,由于此时线程中没有事务,因此抛出异常。
- 传播行为是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED时,如果当前线程中没有事务,则开启一个新的事务(通过
startTransaction
方法)。 - 传播行为是PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER时,如果当前线程没有事务,则方法也不运行在事务中,因此不作任何处理。
由于SpringFramework默认的事务传播行为是PROPAGATION_REQUIRED,因此程序会进行else-if结构中,通过startTransaction
方法开启一个新事务。
(5)开启新事务:startTransaction
源码9:AbstractPlatformTransactionManager.java
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;
}
由 源码9 可知,startTransaction
方法的核心动作是调用doBegin
方法开启事务,该方法定义在DataSourceTransactionManager类中。
源码10:DataSourceTransactionManager.java
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// ......
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
// 从ConnectionHolder中获取到Connection对象
con = txObject.getConnectionHolder().getConnection();
//......
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
// 设置autoCommit属性为false,关闭自动提交,开启事务
con.setAutoCommit(false);
}
// ......
} // catch ...
}
由 源码10 可知,doBegin
方法的核心动作是从DataSourceTransactionObject中取出内部组合的ConnectionHolder,再从ConnectionHolder中取出组合的Connection对象,随后执行setAutoCommit(false)
方法设置autoCommit属性为false,关闭自动提交,开启事务。
10.5.2.2 prepareTransactionInfo
回到 源码3 的createTransactionIfNecessary
方法,getTransaction
方法执行完毕后,开始执行prepareTransactionInfo
方法。
源码11:TransactionAspectSupport.java
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 创建TransactionInfo对象
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// logger ...
// 设置事务信息
txInfo.newTransactionStatus(status);
} else {
// logger ...
}
// 绑定到当前线程中
txInfo.bindToThread();
return txInfo;
}
由 源码11 可知,prepareTransactionInfo
方法会创建一个TransactionInfo对象,把事务状态信息放入其中,并绑定到当前线程中。
当TransactionInfo创建完毕并返回,createTransactionIfNecessary
方法执行完毕,事务也就创建好了。
10.5.2.3 UserServie.test
DeptService的save
方法的事务开启之后,它的内部会调用UserService的test
方法,由于UserServie也是被AOP代理的代理对象,在调用其test
方法时会再次进入createTransactionIfNecessary
方法处理事务逻辑。
由于此时线程中已经存在事务,因此在getTransaction
方法中,会进入到 源码4 的第1个if结构中,即当前已有事务时的传播行为处理(即 源码6 的handleExistingTransaction
方法)。
10.5.2.4 handleExistingTransaction
(1)传播行为PROPAGATION_NEVER的处理
源码13:AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// (1)传播行为PROPAGATION_NEVER的处理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
// throw ex...
}
// ......
}
由 源码13 可知,如果是传播行为PROPAGATION_NEVER,要求线程中不能有事务,所以当线程中已有事务时,会直接抛出异常。
(2)传播行为PROPAGATION_NOT_SUPPORTED的处理
源码14:AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// (1)传播行为PROPAGATION_NEVER的处理...
// (2)传播行为PROPAGATION_NOT_SUPPORTED的处理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
// logger...
// 挂起DeptService的save方法的事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// ......
}
由 源码14 可知,如果是传播行为PROPAGATION_NOT_SUPPORTED,要求方法不能执行在事务中,因此此处会把DeptService的save
方法的事务挂起,并执行UserService的test
方法。
(3)传播行为PROPAGATION_REQUIRES_NEW的处理
源码15:AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// (1)传播行为PROPAGATION_NEVER的处理...
// (2)传播行为PROPAGATION_NOT_SUPPORTED的处理...
// (3)传播行为PROPAGATION_REQUIRES_NEW的处理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
// logger...
// 挂起DeptService的save方法的事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 为UserService的```test```方法开启一个新的事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
} catch (RuntimeException | Error beginEx) {
// 如果UserService的```test```方法抛出异常,则还原外层事务
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// ......
}
如果传播行为是PROPAGATION_REQUIRES_NEW,会挂起之前的事务,并开启一个新的事务。
由 源码15 可知,此处会把DeptService的save
方法的事务挂起,并为UserService的test
方法开启一个新的事务。同时,如果UserService的test
方法抛出异常,则还原外层事务。
(4)传播行为PROPAGATION_NESTED的处理
源码16:AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// (1)传播行为PROPAGATION_NEVER的处理...
// (2)传播行为PROPAGATION_NOT_SUPPORTED的处理...
// (3)传播行为PROPAGATION_REQUIRES_NEW的处理...
// (4)传播行为PROPAGATION_NESTED的处理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 检查是否允许嵌套事务
if (!isNestedTransactionAllowed()) {
// throw ex...
}
// logger...
// 检查是否支持保存点
if (useSavepointForNestedTransaction()) {
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
} else {
// 如果不支持创建保存点,则会开启一个新的事务
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// ......
}
如果传播行为是PROPAGATION_NESTED,则会记录一个保存点,方法继续运行在当前事务上。如果出现异常,不会全部回滚,而是回滚到上一个保存点。
由 源码16 可知,处理逻辑首先会检查是否允许嵌套事务以及是否支持保存点,如果两个条件都成立,则会创建保存点,UserService的test
方法继续运行在当前事务中。
如果不支持创建保存点,则会调用startTransaction
方法开启一个新的事务,相当于降级到了传播行为PROPAGATION_REQUIRES_NEW。
(5)传播行为PROPAGATION_REQUIRED和PROPAGATION_SUPPORTS的处理
源码17:AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// (1)传播行为PROPAGATION_NEVER的处理...
// (2)传播行为PROPAGATION_NOT_SUPPORTED的处理...
// (3)传播行为PROPAGATION_REQUIRES_NEW的处理...
// (4)传播行为PROPAGATION_NESTED的处理...
// (5)传播行为PROPAGATION_REQUIRED和PROPAGATION_SUPPORTS的处理
if (isValidateExistingTransaction()) {
// ...
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
如果程序没有进入(1)-(4)的处理,则会进入最后的处理逻辑,即传播行为PROPAGATION_REQUIRED和PROPAGATION_SUPPORTS的处理。
由 源码17 可知,由于isValidateExistingTransaction
方法默认返回false,因此不会进入if结构,而最后的两行源码是把现有的事务信息封装并返回。
10.5.3 PROPAGATION_REQUIRES_NEW
将UserService的test
方法上的@Transactional注解的事务传播行为改为PROPAGATION_REQUIRES_NEW,并重新执行主启动类。
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void test() {
由 10.5.2 的分析可知,该传播行为下会进入传播行为PROPAGATION_REQUIRES_NEW的处理逻辑,在handleExistingTransaction
方法中挂起之前的事务,并开启一个新的事务,即 源码15 中的逻辑。
10.5.3.1 挂起原事务:suspend
源码18:AbstractPlatformTransactionManager.java
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
// 事务和同步均开启,调用doSuspend方法
suspendedResources = doSuspend(transaction);
}
// ...
} // catch ...
} else if (transaction != null) {
// 事务开启,但同步未开启
// 调用doSuspend方法
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
} else {
// 事务和同步均未开启
return null;
}
}
由 源码18 可知,suspend
方法会检查事务和事务同步是否已开启,如果事务开启了,不管同步是否开启,最终都会调用doSuspend
方法真正挂起事务。doSuspend
的实现在DataSourceTransactionManager类中。
源码19:DataSourceTransactionManager.java
@Override
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
由 源码19 可知,doSuspend
方法将DataSourceTransactionObject对象中的ConnectionHolder设置为null,即移除掉ConnectionHolder对象,然后解除事务同步管理器TransactionSynchronizationManager中的资源绑定。
通过Debug发现,doSuspend
方法返回的是组合了Connection对象的ConnectionHolder对象。
随后,suspend
继续执行,doSuspend
方法返回的ConnectionHolder对象被封装成SuspendedResourcesHolder对象并返回。
10.5.3.2 开启新事务:startTransaction
源码20:AbstractPlatformTransactionManager.java
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// SuspendedResourcesHolder对象被存入TransactionStatus
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启新事务
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
由 源码20 可知,startTransaction
方法的最后一个参数就是上一步返回的SuspendedResourcesHolder对象,该对象被存入了TransactionStatus中,随后调用doBegin
方法开启新事务。
这样做的目的是,当内层新事务执行完成后清理相关的线程同步等信息时,可以从事务状态信息中提取出被挂起的事务,然后恢复外层事务。
10.5.3.3 内层新事务执行完成后的处理
在 SpringBoot源码解读与原理分析(三十三)SpringBoot整合JDBC(二)声明式事务的生效原理和控制流程 10.4.2.5 事务执行的后处理 中提到,无论是成功提交事务(processCommit方法)还是回滚事务(processRollback方法),最终都会执行一个cleanupAfterCompletion
方法。
源码21:AbstractPlatformTransactionManager.java
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
// 组件资源清除
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
// 释放挂起的事务
if (status.getSuspendedResources() != null) {
// logger ...
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
throws TransactionException {
if (resourcesHolder != null) {
// 取出其中的ConnectionHolder对象
Object suspendedResources = resourcesHolder.suspendedResources;
if (suspendedResources != null) {
doResume(transaction, suspendedResources);
}
// ......
}
}
由 源码21 可知,前两个if结构与组件资源清除相关,最后一个if结构用于释放挂起的事务。在resume
方法中,取出SuspendedResourcesHolder对象中封装的ConnectionHolder对象,并调用doResume
方法真正地释放事务。
源码22:DataSourceTransactionManager.java
@Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
由 源码22 可知,doResume
方法会将ConnectionHolder对象重新绑定到事务同步管理器TransactionSynchronizationManager中。
可以发现,doResume
方法的逻辑和doSuspend
方法的逻辑是相反的,doResume
方法中的是bindResource
方法,而doSuspend
方法中的是unbindResource
方法。
等resume
方法执行完毕,原来的外层事务又重新被绑定到线程上,相当于恢复了被挂起之前的状态。
10.6 小结
第10章到此就梳理完毕了,本章的主题是:SpringBoot整合JDBC。回顾一下本章的梳理的内容:
(三十二)SpringBoot整合JDBC(一)JDBC组件的自动装配
(三十二)SpringBoot整合JDBC(二)声明式事务的生效原理和控制流程
(三十四)SpringBoot整合JDBC(三)声明式事务的传播行为控制
更多内容请查阅分类专栏:SpringBoot源码解读与原理分析
第11章主要梳理:SpringBoot整合MyBatis。主要内容包括:
- MyBatis框架概述与工程整合;
- SpringBoot整合MyBatis的核心组件自动装配。