在学习spring事务的时候,一定会涉及到一个概念,无法避免的,就是事务挂起和事务恢复
对于事务挂起和事务恢复,可以简单的描述一下,是这样的
1.首先我们假设有两个类,A类和B类,两个类中的字段是一模一样的,A类表示当前事务,B类表示备份事务
2.如果我开启一个事务,会把当前事务信息,存入到A类中,如果我这时候要进行事务挂起
3.事务挂起:就会把A类中当前事务的信息,赋值到B类中,然后在创建一个新事务的时候,会赋值到A类中
4.恢复事务:如果此时我当前事务执行完毕了,需要恢复原来的事务,就只需要将A类清空,然后将B类中的数据信息赋值到A类,此时A事务就会再次生效

我觉得可以理解为就是倒腾了一手

事务挂起源码

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
我们直接跳入到这个方法中来看,这个方法是在当前事务存在的时候,会进入到这个方法来处理,执行链路是这样的
org.springframework.transaction.interceptor.TransactionInterceptor#invokeorg.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransactionorg.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessaryorg.springframework.transaction.support.AbstractPlatformTransactionManager#getTransactionorg.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

正常的话,一个事务方法的执行是这个链路,自己debug看下即可,但是要进入到这个方法中,有一个前提,就是当前事务已存在,然后又调用了另外一个事务方法,才会进入到这里
我们以PROPAGATION_REQUIRES_NEW这个级别的传播机制为例,为什么以这个为例,因为这个传播机制,在当前事务存在的时候,是会将当前事务挂起,然后开启一个新的事务,也正好可以看下spring是如何挂起事务,并创建新事务的


if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {if (debugEnabled) {logger.debug("Suspending current transaction, creating new transaction with name [" +definition.getName() + "]");}/*** 这里是挂起事务的操作,挂起事务的话,会把事务管理器中的属性设置为null* ,然后将事务管理器中的属性暂时存储到suspendedResourceHolder中*/SuspendedResourcesHolder suspendedResources = suspend(transaction);try {boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 开启事务doBegin(transaction, definition);// 将事务绑定到线程中prepareSynchronization(status, definition);return status;}catch (RuntimeException | Error beginEx) {/*** 如果在开启新的事务的时候,异常了,就会在下面这个方法中,将事务恢复(和上面挂起是相对的)* ,其实就是把suspendResourceHolder中的属性重新赋值到TransactionSynchronizationManager*/resumeAfterBeginException(transaction, suspendedResources, beginEx);throw beginEx;}
}

由于这个方法中,代码比较多,我就删减了一部分,只留下了propagation_requires_new这个传播机制的代码
可以看到,会先调用suspend(transaction)将当前事务挂起,然后再下面的doBegin()再开启一个新的事务,然后通过prepareSynchronization(),将事务相关信息放入到threadLocal中

suspend(transaction)

/**
* 这是挂起事务的源码* 所谓的事务挂起:就是将当前事务管理器中的相关属性,保存到suspendedResourceHolder中*/
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {/*** 1.如果当前事务是active状态,就将事务挂起,挂起的操作其实也简单* 将当前事务的属性信息暂存到SuspendedResourcesHolder中,然后将当前事务的属性设置为null*/if (TransactionSynchronizationManager.isSynchronizationActive()) {List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();try {Object suspendedResources = null;if (transaction != null) {suspendedResources = doSuspend(transaction);}/*** 1.1 下面就是挂起事务的操作,将事务同步管理器中的属性置为null* , 然后将配置信息,存储到suspendedResources中,以便在恢复事务的时候,可以恢复*/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) {/*** 2.如果挂起事务失败,就需要进行回滚,就是将suspendedResourcesHolder* 中的属性重新赋值到TransactionSynchronizationManager中*/// doSuspend failed - original transaction is still active...doResumeSynchronization(suspendedSynchronizations);throw ex;}}else if (transaction != null) {// Transaction active but no synchronization active.Object suspendedResources = doSuspend(transaction);return new SuspendedResourcesHolder(suspendedResources);}else {// Neither transaction nor synchronization active.return null;}
}

这是suspend的源码,可以看到,在1.1这个注释位置,会获取到当前事务的属性信息,然后在下面,会new SuspendedResourcesHolder(),将当前事务属性信息放入到这里面
再下面,就是一些异常的判断和处理,我们可以认为,这个方法就是把事务的属性信息存入到了SuspendedResourcesHolder对象中

newTransactionStatus()

这个方法也很重要,会把刚才创建的suspend对象,放入到DefaultTransactionStatus类中,这里我猜是为了在后面事务恢复的时候用的

doBegin()

在doBegin()方法中,主要是重新获取一个数据库连接,然后设置连接的相关信息,比如:非自动提交等
然后将连接信息存入到TransactionSynchronizationManager对象中
我们可以简单认为doBegin()就是重新开启了一个事务连接

事务恢复

前面讲的是事务挂起,下面来说事务恢复,事务恢复,就是在事务提交或者回滚的时候,会进行事务恢复的处理

这里直接贴了一张图,是事务提交和事务回滚的处理流程,最终都会调用到cleanupAfterCompletion()方法,这个方法就是事务恢复的代码

private void cleanupAfterCompletion(DefaultTransactionStatus status) {status.setCompleted();if (status.isNewSynchronization()) {TransactionSynchronizationManager.clear();}if (status.isNewTransaction()) {doCleanupAfterCompletion(status.getTransaction());}if (status.getSuspendedResources() != null) {if (status.isDebug()) {logger.debug("Resuming suspended transaction after completion of inner transaction");}Object transaction = (status.hasTransaction() ? status.getTransaction() : null);resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());}}

在这个代码中,前面是一些逻辑处理,应该是对当前事务进行清除的操作,需要关注的是最后一行代码,resume()方法

protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)throws TransactionException {if (resourcesHolder != null) {Object suspendedResources = resourcesHolder.suspendedResources;if (suspendedResources != null) {doResume(transaction, suspendedResources);}List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;if (suspendedSynchronizations != null) {TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);doResumeSynchronization(suspendedSynchronizations);}}}

这里可以看到,是从resourcesHolder中取一些参数赋值到TransactionSynchronizationManager中;SuspendedResourcesHolder是哪个对象呢?就是前面事务挂起的时候,将当前事务参数信息赋值到的一个对象

所以:我们可以认为,事务挂起就是将事务赋值到一个临时对象中,事务恢复就是从临时对象中,将事务属性信息赋值到当前事务中

spring事务之事务挂起和事务恢复源码相关推荐

  1. 简单开源java ssm_[VIP源码]【S006】SSM(Spring+Spring MVC+Mybatis) java开源博客管理系统项目源码...

    java源码项目名称:SSM(Spring+Spring MVC+Mybatis) java开源博客管理系统项目源码  java项目源码 1 ?, R, _* q  n8 v) S$ R7 ?百度网盘 ...

  2. Spring学习总结(29)——Spring异步处理@Async的使用以及原理、源码分析(@EnableAsync)

    在开发过程中,我们会遇到很多使用线程池的业务场景,例如异步短信通知.异步记录操作日志.大多数使用线程池的场景,就是会将一些可以进行异步操作的业务放在线程池中去完成.例如在生成订单的时候给用户发送短信, ...

  3. 基于spring boot 的学生科研项目共享平台毕业设计源码271611

    springboot学生科研项目共享平台 摘 要 随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联网系统,并对其进行维护和管理.在现实运用中,应用软件的工作规 ...

  4. spring boot信佳玩具有限公司仓库管理系统毕业设计源码011553

    Springboot信佳玩具有限公司仓库管理系统 摘要 本论文主要论述了如何使用java语言开发一个Springboot信佳玩具有限公司仓库管理系统,本系统将严格按照软件开发流程进行各个阶段的工作,采 ...

  5. spring boot大学生就业质量调查分析系统 毕业设计-附源码161457

    大学生就业质量调查分析系统 摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题 ...

  6. Spring的Autowired自动装配(XML版本+Annotation版本+源码+解析)

    http://moshowgame.iteye.com/blog/1607718 @Autowired自动装配 上面的例子我们用的都是手动装配的,如果DAO-Service一多那就很麻烦了,那么我们需 ...

  7. Spring Data Redis—Pub/Sub(附Web项目源码)

    一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...

  8. Spring Security之过滤器链【探案】+源码剖析

    Spring Security之过滤器链[探案] Spring Security常用过滤器介绍 过滤器是一种典型的AOP思想,关于什么是过滤器,就不赘述了,接下来咱们就一起看看Spring Secur ...

  9. Spring Boot整合JWT实现用户认证(附源码)

    点击上方"程序IT圈",选择"置顶公众号" 每天早上8点50分进来看看,就是最大的支持 来源:https://dwz.cn/yv1Do6e3 什么是JWT JW ...

最新文章

  1. Java中的集合类--复习
  2. 2018java多线程面试题_2018JAVA面试题附答案
  3. 在华为云服务器的Linux系统中搭建开发环境
  4. mysql 10分钟_10分钟入门mysql(含常用的sql语句,mysql常见问题及解决方案)
  5. 重写Oracle的wm_concat函数,自定义分隔符、排序
  6. Android开发之AlertDialog设置左右边距的间接办法
  7. NCPC2018 D.Delivery Delays[二分答案+DP check]
  8. MySQL笔记汇总---狂神说
  9. 【ZOJ - 2955】Interesting Dart Game(背包,结论,裴蜀定理,数论)
  10. 信号与槽是如何实现的_如何解决wifi信号不好,实现全面覆盖
  11. 关于使用MYSQL出现的内存泄漏问题
  12. 向右键添加新建脚本菜单
  13. mongodb笔记 getting started
  14. Flutter小说APP
  15. 在AndroidStudio中使用ARCore
  16. 第2章 大数据可视化基础
  17. 计算机体系结构-第五章-指令级并行
  18. 一开机checkingmedia_电脑开机出现checking media怎么办?
  19. c语言经典程序100例 九宫格,9X9,九宫格测试,C编程。
  20. 餐饮店的会员充值消费系统一般用哪个?

热门文章

  1. java基础知识总结 超详细
  2. Android系统开发 默认壁纸的定制 主题风格的开发及定制 DDMS 常用adb 命令 抓取Log
  3. C/C++中 宏定义字符串 操作
  4. 国家电网调控人工智能创新大赛开启 百度飞桨提供国产AI平台
  5. pyaudio:基于pyaudio利用Python编程实现播放音频mp3、wav等格式文件
  6. 访问学者在美国访学生活有哪些常识?
  7. 如何将Excel中隐藏的列显示出来
  8. 04 DIY流星观测站——镜头简介
  9. 计算机ppt操作知识,计算机基础知识.ppt.ppt
  10. ROS入门(ROS安装+编译器配置)详细教程 ROSneotic安装 VScode的ROS开发环境的简单配置