当前位置:首页 > 杂谈 > 正文内容

鬣狗技术- spring|spring-tx的秘密-鬣狗bot

2023-07-16 09:24:39TONY杂谈122

健康生活、快乐学习、深度思考

大厂深耕多年,技术不断学习迭代并且深入研究,热爱技术,热爱开源

右上角⬆️点击关注➕,一起进步,关注作者并获取最新技术资讯和技术文章;持续更新有思考深度的文章和技术。

作者:鬣狗

日期:2021年8月22日

0.简介

本篇将介绍Spring事务框架的运行原理,包括Spring事务框架实现原理、事务传播行为等

1.原理和架构

Spring-Tx技术原理的本质的AOP+ThreadLocal。通过AOP技术生成拦截器对业务方法的拦截来达到事务的提交和回滚以及Spring事务传播的实现。ThreadLocal用来存放当前线程使用的数据库连接对象以及额外资源。

图1 TransactionIntecetor类继承图

如图1是类TransactionInterceptor类的继承关系图,TransactionInteceptor类的作用就是根据Spring的事务传播属性来实施具体的拦截策略。可以看到这个类实现了MethodInteceptor接口,并且继承了TransactionAspectSupport,说明TransactionIntceptor本身就是个切面。TransactionAspectSupport类作为事务切面的基类,规定了事务执行的骨架,抽象如下:

// get current transaction determined by transaction propagation

Transaction tx = getTransaction();

try

{

invokeMethod(); // execute method }catch(Exception

e){

rollback(); // rollback }finally

{

cleanUp(); // clean up the resouce used or reset the tx-info

}

// commit the statement ignore the exceptioncommitTransactionAfterReturning();

step 1. 首先根据spring事务的传播属性获取当前的事务

step 2. try:在当前的事务下执行业务方法

step 3. catch:如果执行出错,则回滚事务

step 4. finally:最后不管事务是否执行成功,做一些资源清理的工作

step 5. 最后方法执行完毕后提交当前事务

以上就是spring-tx的基本思想。

图2 Spring-Tx核心代码结构

如上图是Spring-Tx的代码架构。其中PlatformTransactionManager类是Spring-Tx中的中心接口。

图3 PlatformTransactionManager类

PlatformTransactionManager类只有三个方法:

getTransaction

commit

rollback

AbstractPlatformTransactionManager继承了PlatformTransactionManager并且实现了Spring的标准事务工作流(Spring’s standard transaction workflow --- 也就是上文提到的工作流程)。并且提供以下的功能:

determines if there is an existing transaction

applies the appropriate propagation behavior

suspends and resumes transactions if necessary

checks the rollback-only flag on commit

trrigger registered synchronization callbacks if transaction synchronization is active

其中

TransactionSynchronization类似回调函数的作用,其中定义的方法有resume、suspend、beforeCommit、beforeCompetition、afterCommit、afterCompetition。这些方法被调用的时机正如其方法名称一样,例如afterCommit,这个方式是在事务提交后执行。

在仔细分析spring-tx代码之前,我们首先认识下spring-tx出现的重要的类的概念:

名词

概念

PlatformTransactionManager

事务管理器,管理事务的各生命周期方法,下文简称TxMgr

TransactionAttribute

事务属性, 包含隔离级别,传播行为,是否只读等信息,下文简称TxAttr

TransactionStatus

事务状态,下文简称TxStatus

TransactionInfo

事务信息,内含TxMgr, TxAttr, TxStatus等信息,下文简称TxInfo

TransactionSynchronization

事务同步回调,内含多个钩子方法,下文简称TxSync / transaction synchronization

TransactionSynchronizationManager

事务同步管理器,维护当前线程事务资源,信息以及TxSync集合

其中TransactionAttribute和TransactionStatus去区分开来,TransactionAttribute是事务当前的属性,如隔离级别、传播属性、read-only等。而TransactionStatus表示事务的状态,如当前事务是否是新事务,事务是否有savepoint,事务是否已经完成。

备注:表格出自

https://www.cnblogs.com/micrari/p/7612962.html,如有侵权,请联系作者。

代码分析:

从TransactionInterceptor入手:

图4 invoke方法

TransactionInteceptor的invoke方法是对业务方法的一个拦截,然后把具体的拦截逻辑交给TransactionAspectSupport的invokeWithinTransaction进行处理。

TransactionAspectSupport.invokeWithinTransaction

图5 invokeWithinTransaction

方法invokeWithinTransaction规定了spring-tx事务处理的框架。首先获取当前事务,然后执行方法,执行出现异常之后进行回滚,清理资源,最后提交事务。

createTransactionIfNecessary

该方法会根据当前的事务属性来决定是否创建一个新的事务。

图6 createTransactionIfNecessary

该方法通过

PlatformTransactionManager.getTransaction()方法来获取当前事务,该方法会根据事务的传播属性来决定是否获取事务。下面是该方法的具体实现。

AbstractPlatformTransactionManager#getTransaction

@Overridepublic final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException

{

Object transaction = doGetTransaction();

// Cache debug flag to avoid repeated checks. boolean

debugEnabled = logger.isDebugEnabled();

if (definition == null

) {

// Use defaults if no transaction definition given. definition = new

DefaultTransactionDefinition();

}

if

(isExistingTransaction(transaction)) {

// Existing transaction found -> check propagation behavior to find out how to behave. return

handleExistingTransaction(definition, transaction, debugEnabled);

}

// Check definition settings for new transaction. if

(definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {

throw new InvalidTimeoutException("Invalid transaction timeout"

, definition.getTimeout());

}

// No existing transaction found -> check propagation behavior to find out how to proceed. if

(definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

throw new

IllegalTransactionStateException(

"No existing transaction found for transaction marked with propagation mandatory"

);

}

else if

(definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

SuspendedResourcesHolder suspendedResources = suspend(null

);

if

(debugEnabled) {

logger.debug("Creating new transaction with name [" + definition.getName() + "]: "

+ definition);

}

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 ex) {

resume(null

, suspendedResources);

throw

ex;

}

catch

(Error err) {

resume(null

, suspendedResources);

throw

err;

}

}

else

{

// Create "empty" transaction: no actual transaction, but potentially synchronization. boolean

newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null

);

}

}

备忘录模式的使用

图7 TransactionInfo

TransactionInfo里面有一个oldTransactionInfo属性,该属性是用来保存方法执行前的事务信息的。例如:方法A调用方法B,B的事务传播属性是REQUIRED_NEW。执行方法A时,假设事务属性是TxInfoA,此时当前的事务属性就是TxInfoA。当执行到方法B时,会创建一个新的TxInfoB来作为当前的事务属性,并且TxInfoB中的oldTransactionInfo就是TxInfoA,当方法B执行完毕之后,会将oldTransactionInfo恢复为当前的事务属性。

ThreadLocal的使用

图8 TransactionSynchronizationManager

spring-tx中使用ThreadLocal来保存当前事务的资源,具体是放在

TransactionSynchronizationManager类中。具体包括当前的连接、事务名称、事务隔离级别、当前事务是否活跃以及事务同步回调。 3.事务传播属性

REQUIRED

如果当前无事务则开启一个事务,否则加入当前事务。

SUPPORTS

如果当前有事务则加入当前事务。

MANDATORY

如果当前无事务则抛出异常,否则加入当前事务。

REQUIRES_NEW

如果当前无事务则开启一个事务,否则挂起当前事务并开启新事务。

NOT_SUPPORTED

如果当前有事务,则挂起当前事务以无事务状态执行方法。

NEVER

如果当前有事务,则抛出异常。

NESTED

创建一个嵌套事务,如果当前无事务则创建一个事务。

图9 tx-propagation

为了方便记忆,我做了上面的图。可以看到REQUIRED、REQUIRED_NEW、NESTED都需要事务;SUPPORT、NOT_SUPPORT,则对事务是否存在要求不高;而MADTORY、NEVER分别代表了两个极端,一个是必须有事务,一个是必须没有事务。

所以可以有如下记法:最左边是需要以事务的方式执行,中间对事务的要求不高,而最右则比较极端。

REQUIRED、REQUIRED_NEW、NESTED <----- SUPPORTED、NOT_SUPPORTED --> MANDATORY、NEVER

4.XA事务

XA是由X/Open组织提出的分布式事务的规范。XA规范主要定义了(全局)事务管理器(TM)和(局 部)资源管理器(RM)之间的接口。主流的关系型 数据库产品都是实现了XA接口的。

图10 XA事务

备注:图片来自

https://blog.csdn.net/wuzhiwei549/article/details/79925618

XA事务主要就是2PC(2阶段提交)的一个实现,其中TM是全局的事务管理器,用来管理全局事务。RM是本地资源管理器,用来管理本地事务。应用程序首先要向TM中注册资源,然后才能对资源进行操作。

5.Mybatis是怎么和Spring-Tx交互的

疑问:有没有想过这样一个问题,spring集成mybatis时,mybatis是怎么获取到当前的数据库连接的呢,带着这个疑问,我们来思考这个问题。

我们知道Mybatis的核心是SqlSessionFactory,用这个类来获取SqlSession对象,SqlSession对象可以理解成一个数据库连接,通过这个连接可以执行Sql,然后转换结果。

图11 DefaultSqlSessionFactory

这个方法通过

TransactionFacotry.newTransaction来获取当前事务。

图12 TransactionFactory

如图12,TransactionFactory有三个子类,其中SpringManagedTransaction就是我们要招的类。

图13 SpringManagedTransaction

可以看到Mybatis是使用的Spring-Tx提供的DataSoureUtils类来获取当前的连接。

图14 DataSourceUtils

图14是

DataSourceUtils.doGetConnection方法,其实就是拿的TransctionSynchronizationManager.getResource方法,也就是获取当前线程的连接。

所以总结起来就是,spring集成mybatis时,mybatis使用的是spring提供的DataSourceUtils类来获取当前线程的连接。

作者心得:应该说工作之后能力还是有提高的,在读研期间,这种源码根本就读不懂。但是工作后,也能够读懂这些框架的源码了。spring-tx也是看了有两周,过程中也是有不懂的地方,对于我来说,不懂的我会把它当成一个点,去”定点爆破“,会把这个问题记到脑子里面,会有一段时间都在思考这个点,去搜集资料,反复阅读源码。spring-tx这篇文章我总结了两个阅读源码的方法:

要站在更高的层次看源码,刚开始不要去纠结其具体的实现细节,首先把代码的整体架构梳理出来;看看这个代码具体是解决了哪些问题,提供了哪些能力。

要站在更高的层次看问题,要在宏观上看待问题,而不要去纠结于细节。

6.其它

github主页:

https://github.com/youngFF

git仓库地址:

https://github.com/youngFF/MyHearthStone.git

gitbook地址:

https://youngff.github.io/MyHearthStone/

欢迎各位加入鬣狗技术社区,希望能够为您提供有思考、有深度的文章。欢迎加入我们,如果你也有想法在鬣狗技术社区发表文章,头条私聊即可。

求 关注➕转发➕点赞,谢谢各位!您的支持就是我们更新的动力

“鬣狗技术- spring|spring-tx的秘密-鬣狗bot” 的相关文章

百度怎么从百度联盟赚钱?该业务占百度总收入大概有多少?是不是等同于百度为客户提供广告位?

百度怎么从百度联盟赚钱?该业务占百度总收入大概有多少?是不是等同于百度为客户提供广告位?

百度联盟对百度的意义有两个,首先是巩固百度搜索的地位,第二是赚钱。 百度变现能力最高的流量是搜索流量,搜索推广(就是以前叫竞价排名那个)是最主要的收入来源。所以,巩固百度搜索的地位,保持和提升百度搜索的流量,非常重要。...

ToDesk再次升级,打通手机电脑、平板多端设备互控

ToDesk再次升级,打通手机电脑、平板多端设备互控

原标题:ToDesk再次升级,打通手机电脑、平板多端设备互控 随着各种智能设备应用功能和场景的持续扩展,手机、笔记本、平板以及台式电脑之间的远控互联越来越高频,但不同设备之间的操作割裂以及底层逻辑不合,导致远控过程卡顿、不跟手,最终给用户带来糟糕的体验。为了解决用户痛点,ToDe...

封禁抖音登录入口,腾讯开始自闭?

封禁抖音登录入口,腾讯开始自闭?

“抖音大战微信”跟当年“3Q大战”不一样,并非单纯出于公司竞争而发生矛盾,也有用户自然发觉的矛盾。...

登录抖音小店官网,开启电商新机遇

登录抖音小店官网,开启电商新机遇

全球线上零售TOP10国家中,中国连续七年位居榜首,根据eMarketer数据显示,2021年中国线上零售仍会保持21%的高增长率。其中,直播电商大大缩短了消费链路,这也使得众多实体商家看到了电商产业的好处,纷纷想要入驻抖店,从抖音小店官网如何开店注册呢?这也是很多人关心的问题。...

3月中国70城新房价格:逾九成城市环比上涨 创近4年新高

3月中国70城新房价格:逾九成城市环比上涨 创近4年新高

  中新社北京4月15日电 (记者 庞无忌)3月,中国70个大中城市房价明显升温。 资料图:房地产楼盘。中新社记者 张斌 摄   中国国家统计局15日发布的数据显示,2023年3月份,中国70个大中城市中,新建商品住宅和二手住宅销售价格环比上涨城市分别有64个和57个,比...

“人民艺术家”秦怡辞世享年100岁:一生都在追求中

“人民艺术家”秦怡辞世享年100岁:一生都在追求中

作者高志苗王笈 “一生都在追求中,活得越老,追求越多。”2012年,秦怡曾如是写道。 记者从上影集团了解到,中国百年电影史的见证者和耕耘者、被称为“人民艺术家”和“最美奋斗者”的秦怡,5月9日4时08分在复旦大学附属华东医院逝世,享年100岁。 资料图片为2012年...