SpringBoot源码解读与原理分析(三十四)SpringBoot整合JDBC(三)声明式事务的传播行为控制

文章目录

    • 前言
    • 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种传播行为:

源码1TransactionDefinition.javaint 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:嵌套。如果当前没有事务运行,则会开启一个新的事务;如果当前已有事务运行,则会记录一个保存点,方法继续运行在当前事务中。如果方法出现异常,则不会全部回滚,而是回滚到上一个保存点。

简单总结如下:

REQUIREDSUPPORTSMANDATORYREQUIRES_NEWNOT_SUPPORTEDNEVERNESTED
已有事务运行运行当前事务运行当前事务运行当前事务挂起原事务,开启新事务;新事务运行完后释放原事务挂起原事务,然后不运行事务抛出异常记录保存点,继续运行当前事务,如果出现异常则回滚到保存点
没有事务运行开启新事务不运行事务抛出异常开启新事务不运行事务不运行事务开启新事务

10.5.1 修改测试代码

(1)新建一个Service类,并引用UserService
@Service
public class DeptService {@Autowiredprivate 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方法。

源码2TransactionAspectSupport.javaprotected 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 ......
}
源码3TransactionAspectSupport.javaprotected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {// 如果事务定义中没有指定name,则将方法名作为事务定义nameif (txAttr != null && txAttr.getName() == null) {txAttr = new DelegatingTransactionAttribute(txAttr) {@Overridepublic 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)获取事务
源码4AbstractPlatformTransactionManager.javapublic 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中。

源码5DataSourceTransactionManager.javaprotected 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)当前已有事务时的传播行为处理
源码6AbstractPlatformTransactionManager.javapublic final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)throws TransactionException {// (1)获取事务 ...// (2)当前已有事务时的传播行为处理if (isExistingTransaction(transaction)) {return handleExistingTransaction(def, transaction, debugEnabled);}// ......
}

由于在执行DeptService的save方法之前,当前线程还没有开启事务,因此该if判断的结果为false,不会进入handleExistingTransaction方法。

(3)超时检测
源码7AbstractPlatformTransactionManager.javapublic 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)当前事务不存在时的传播行为处理
源码8AbstractPlatformTransactionManager.javapublic 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
源码9AbstractPlatformTransactionManager.javaprivate 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类中。

源码10DataSourceTransactionManager.javaprotected 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方法。

源码11TransactionAspectSupport.javaprotected 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的处理
源码13AbstractPlatformTransactionManager.javaprivate 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的处理
源码14AbstractPlatformTransactionManager.javaprivate 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的处理
源码15AbstractPlatformTransactionManager.javaprivate 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的处理
源码16AbstractPlatformTransactionManager.javaprivate 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的处理
源码17AbstractPlatformTransactionManager.javaprivate 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
源码18AbstractPlatformTransactionManager.javaprotected 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类中。

源码19DataSourceTransactionManager.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对象。

doSuspend方法返回ConnectionHolder对象
随后,suspend继续执行,doSuspend方法返回的ConnectionHolder对象被封装成SuspendedResourcesHolder对象并返回。

10.5.3.2 开启新事务:startTransaction
源码20AbstractPlatformTransactionManager.javaprivate TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);// SuspendedResourcesHolder对象被存入TransactionStatusDefaultTransactionStatus 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方法。

源码21AbstractPlatformTransactionManager.javaprivate 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方法真正地释放事务。

源码22DataSourceTransactionManager.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的核心组件自动装配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/703972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用于自监督视觉预训练的屏蔽特征预测

Masked Feature Prediction for Self-Supervised Visual Pre-Training 一、摘要 提出了用于视频模型自监督预训练的掩模特征预测&#xff08;MaskFeat&#xff09;。首先随机屏蔽输入序列的一部分&#xff0c;然后预测屏蔽区域的特征。研究了五种不同类型的特征&#xff0c;发…

遥感、航拍、影像等用于深度学习的数据集集合

遥感图像的纹理特征异常繁杂&#xff0c;地貌类型多变&#xff0c;人工提取往往存在特征提取困难和特征提取不准确的问题&#xff0c;同时&#xff0c;在这个过程中还会耗费海量的人力物力。随着计算力的突破、数据洪流的暴发和算法的不断创新&#xff0c;在具有鲜明“大数据”…

ffmpeg的pcm、yuv小知识点

ffmpeg的pcm、yuv小知识点 pcm、yuv保存调用&#xff0c;写个通用工具方法&#xff0c;平时快速保存&#xff0c;和调用方便查看自己bug ffmpeg的AVFrame存储 yuv 调用方法 保存方法 void save_yuv420p_file(unsigned char *y_buf , unsigned char *u_buf,unsigned char *…

git commit 后,本地远端都没有记录,消失不见

今天git commit 之后发现远端没有记录&#xff0c;本地没有最新代码记录 git commit 后&#xff0c;提交记录会消失不见的原因可能是&#xff1a; git只git commit了&#xff0c;没有push到远程分支&#xff0c;切换到其他分支时丢失。而且看不到提交记录&#xff0c;和找不到…

2024.2.21 模拟实现 RabbitMQ —— 实现转发规则

目录 需求分析 直接交换机&#xff08;Direct &#xff09; 主题交换机&#xff08;Topic &#xff09; 扇出交换机&#xff08;Fanout &#xff09; Topic 交换机转发规则 routingKey 组成 bindingKey 组成 匹配规则 情况一 情况二 情况三 实现 Router 类 校验 b…

Spring Boot application.properties和application.yml文件的配置

在Spring Boot中&#xff0c;application.properties 和 application.yml 文件用于配置应用程序的各个方面&#xff0c;如服务器端口、数据库连接、日志级别等。这两个文件是Spring Boot的配置文件&#xff0c;位于 src/main/resources 目录下。 application.properties 示例 …

vue中动态表格中文校验,但是中文的参数无法获取

场景&#xff1a; 解决方案&#xff1a; 因为上述的正则表达式后&#xff0c;使用搜狗输入法没有问题&#xff0c;但采用微软自带输入法后&#xff0c;会存在输入数字及英文时为正常&#xff0c;切换为汉字后&#xff0c;会存在吞并当前光标前的字符。具体吞并个数和输入法中有…

Unity发布webgl获取浏览器的URL

Unity发布webgl获取浏览器的URL Unity发布webgl之后获取浏览器的url 在unity中创建文件夹Plugins&#xff0c;然后添加添加文件UnityGetBrowserURL.jslib var GetUrlFunc {//获取地址栏的URLStringReturnValueFunction: function () {var returnStr window.top.location.hre…

SpringBoot3整合Swagger3,访问出现404错误问题(未解决)

秉承着能用就用新的的理念&#xff0c;在JDK、SpringBoot、SpringCloud版本的兼容性下&#xff0c;选择了Java17、SpringBoot3.0.2整合Swagger3。 代码编译一切正常&#xff0c;Swagger的Bean也能加载&#xff0c;到了最后访问前端页面swagger-ui的时候出现404。 根据网上资料…

Oracle ADG相关介绍

文章目录 一、ADG原理1、ADG介绍2、ADG搭建流程 二、ADG相关参数三、增量修复 一、ADG原理 1、ADG介绍 Oracle ADG&#xff08;Advanced Data Guard&#xff09;是Oracle数据库的一项高可用和灾难恢复技术&#xff0c;它通过将数据保持在物理备库中来提供数据保护和容灾能力。…

StringBuffer StringBuilder

String 为什么StringBuilder是线程不安全的&#xff1f;StringBuffer是线程安全的&#xff1f; - Jacian - 博客园 (cnblogs.com) StringBuilder 线程安全的可变字符学序列 速度快 StringBuffer 线程不安全的可变字符序列 创建StringBuilder对象 new StringBuilder&…

c++面试一

1.#include使用 在C/C中&#xff0c;#include 预处理指令用于包含头文件&#xff0c;这些头文件通常包含了函数声明、宏定义以及其他的声明和定义。#include 指令后面跟着的文件名可以使用双引号 "" 或尖括号 <> 来指定&#xff0c;它们之间有一些区别。 双引…

Qt QWiget 实现简约美观的加载动画 第三季

&#x1f603; 第三季来啦 &#x1f603; 这是最终效果: 只有三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QVBoxLayout> #include <QGridLayout> int main(int argc, char *argv[]…

设计并实现一个并发安全的LRU(Least Recently Used,最近最少使用)缓存结构

文章目录 前言实战演示写在最后 前言 相信很多人都使用过LinkedHashMap&#xff0c;LinkedHashMap中的removeEldestEntry可以删除老旧的元素&#xff0c;我们可以以此来实现一个LRU缓存结构&#xff0c;并结合java中JUC包中的各种多线程锁机制来保证多线程安全。 以下是我遇见…

【前端素材】推荐优质后台管理系统Dashmin平台模板(附源码)

一、需求分析 后台管理系统在多个层次上提供了丰富的功能和细致的管理手段&#xff0c;帮助管理员轻松管理和控制系统的各个方面。其灵活性和可扩展性使得后台管理系统成为各种网站、应用程序和系统不可或缺的管理工具。 后台管理系统是一种具有多层次结构的软件系统&#xf…

邀请函 | 2024年数据技术嘉年华集结号已吹响,期待您参会!

龙腾四海内&#xff0c;风云际会时&#xff0c;2024年中国数据嘉年华如约而至。从起初小范围的网友聚会&#xff0c;到如今面向全国各地从业者、爱好者的年度集会&#xff0c;纵使岁月更迭&#xff0c;我们初心依旧。我们在各自最好的年华里共同见证了中国数据库行业的蓬勃发展…

Linux下的IO多路复用

文章目录 一. IO的概念和分类1. IO操作的原理&#xff1a;二. I/O多路复用使用场景和作用1. 问题&#xff1a; 一台网络服务器需要接收100台客户端的连接和数据通信&#xff0c;应该如何设计和实现&#xff1f;2. I/O多路复用机制&#xff1a; 三. Select poll epollselectpoll…

【前端素材】推荐优质后台管理系统Modernize平台模板(附源码)

一、需求分析 后台管理系统是一种用于管理和控制网站、应用程序或系统后台操作的软件工具&#xff0c;通常由授权用户&#xff08;如管理员、编辑人员等&#xff09;使用。它提供了一种用户友好的方式来管理网站或应用程序的内容、用户、数据等方面的操作&#xff0c;并且通常…

光学3D表面轮廓仪微纳米三维形貌一键测量

光学3D表面轮廓仪(白光干涉仪)利用白光干涉原理&#xff0c;以0.1nm分辨率精准捕捉物体的表面细节&#xff0c;实现三维显微成像测量&#xff0c;被广泛应用于材料学领域的研究和应用。 了解工作原理与技术 材料学领域中的光学3D表面轮廓仪&#xff0c;也被称为白光干涉仪&am…

SpringBoot -【SmartInitializingSingleton】基础使用及应用场景

SmartInitializingSingleton 在继续深入探讨 SmartInitializingSingleton接口之前&#xff0c;让我们先了解一下 Spring Framework 的基本概念和背景。Spring Framework 是一个开源的 JavaEE&#xff08;Java Enterprise Edition&#xff09;全栈&#xff08;full-stack&#x…