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

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

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

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

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

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

作者:鬣狗

日期: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” 的相关文章

投资者提问:智能客服机器人聊天系统“申小蜜”已覆盖600+申通网点、1.7...

投资者提问:智能客服机器人聊天系统“申小蜜”已覆盖600+申通网点、1.7...

投资者提问: 智能客服机器人聊天系统“申小蜜”已覆盖600+申通网点、1.7W+商家、1500多位网点客服、3.7W+商家客服,1.24W+客户群。接下来,“申小蜜”将融入申通的网点管家系统,服务数千网点客服和数十万商家,实现申通全国网点覆盖。 请问以上是...

58同城:已在近50个城市上线“直播讲房”

58同城:已在近50个城市上线“直播讲房”

中证网讯(记者 董添)2月19日,58同城、安居客宣布,2月18日起,公司在北京、上海、广州、深圳、成都、杭州等近50个城市陆续上线房产经纪人“直播讲房”功能,帮助经纪人足不出户直播带看,为用户带来身临其境的线上看房体验。 据58同城介绍,经纪人通过登录移动经纪人APP,进入“直播...

楼市进入复苏通道,一二线城市2月房价环比均上涨

楼市进入复苏通道,一二线城市2月房价环比均上涨

界面新闻记者 | 杨冰柯 界面新闻编辑 | 无论是房价还是销售数据,热点城市楼市均迎来小阳春。 3月16日,国家统计局发布2月70个大中城市商品住宅销售价格指数。2月份一、二、三线新房价格环比全部上涨;二手房环比上,一线和二线城市房价环比上涨,三线城市房价环比持平...

香港公司开汇丰银行公司户资料分享

香港公司开汇丰银行公司户资料分享

与其他银行相比,汇丰银行更麻烦。自从被罚款以来,它已经调整了账户,筛选客户,降低风险。 事实上,银行的要求是证明公司是否真的做生意。所有在香港汇丰银行开设H的客户都需要为真正的贸易客户提供相关证明。 目前,基本上所有的银行都是这样的。无论是个人还是公司在开设香港银行账户H时...

爱普生打印机维修记

爱普生打印机维修记

像我这种人,喜欢读些闲书的,但是又不想买纸书(搬家太累),所以做法都是电子书买完,去DRM,然后打印出来。纸不花钱,墨五六块钱一瓶,能打3、4本书。 一台打印机用了7、8年,小毛病都是自己搞。 今天的毛病是,提示墨水用完了,加完墨还是不能打印,问题就出在我用的不是原装正品墨...

强烈推荐3个网站工具,手机也可以用,爆赞

强烈推荐3个网站工具,手机也可以用,爆赞

很久没给各位小伙伴分享办公神器了!最近有关注的朋友询问起。 所以,今天给各位分享一些自己收藏的神器,给有需要的朋友提供方便。 推荐3个好用的在线网站工具,也是我近期常用的网站,感兴趣的可以收藏了。1. 小米风格logo生成器https://mi-logo.lvwzhen.c...