<返回更多

Spring底层事务原理

2022-12-11    海强旅行
加入收藏

一、@EnableTransactionManagement工作原理

开启Spring事务本质上就是增加了一个Advisor,但我们使用 @EnableTransactionManagement注解来开启Spring事务是,该注解代理的功能就是向Spring容器中添加了两个Bean:

(1)AutoProxyRegistrar

(2)ProxyTransactionManagementConfiguration

1

2

(1)AutoProxyRegistrar

主要的作用是向Spring容器中注册了一个InfrastructureAdvisorAutoProxyCreator的Bean。

而InfrastructureAdvisorAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator,所以这个类的主要作用就是开启自动代理的作用,也就是一个BeanPostProcessor,会在初始化后步骤中去寻找Advisor类型的Bean,并判断当前某个Bean是否有匹配的Advisor,是否需要利用动态代理产生一个代理对象。

(2)ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

二、Spring事务基本执行原理

一个Bean在执行Bean的创建生命周期时,会经过InfrastructureAdvisorAutoProxyCreator的初始化后的方法,会判断当前Bean对象是否BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配逻辑为判断该Bean的类上是否存在@Transactional注解,或者类中的某个方法上是否存在@Transactional注解,如果存在则表示该Bean需要进行动态代理产生一个代理对象作为Bean对象。

该代理对象在执行某个方法时,会再次判断当前执行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法,

执行基本流程为:

利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接

修改数据库连接的autocommit为false

执行MethodInvocation.proceed()方法,简单理解就是执行业务方法,其中就会执行sql

如果没有抛异常,则提交

如果抛了异常,则回滚

三、Spring事务的过程

1、数据库:建立连接、开启事务、进行sql操作、成功提交、失败回滚

2、业务逻辑:准备工作(可以进行前置通知)、开启事务、事务操作、成功提交(可以后置通知)、失败回滚(异常通知)

spring的事务是由aop实现的,首先要生成具体的代理对象,然后按照aop流程执行具体

的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务部署通过通知来实现的,

而是通过TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑。

步骤如下:

1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务。

2、当需要开启的时候获取数据库连接,关闭自动提交功能,开启事务。

3、执行具体的sql逻辑操作,在操作的过程中如果执行失败会通过 completeTransactionafterthrowing来完成事务的回滚操作,回滚的

具体逻辑是通过dorollback方法实现,实现时也要先获取连接对象,

然后通过连接对象进行回滚(conn.rollback)。

4、如果执行成功,那么通过completeTransactionafterrunning来完成事务的提交操作,

具体逻辑是通过docommit方法来实现,实现的时候也是先获取连接,通过连接对象来

进行提交(conn.commit)。

5、最后事务执行完毕需要清除事务相关的事务信息(cleanupTransactioninfo)。

四、Spring事务传播机制

在开发过程中,经常会出现一个方法调用另外一个方法,那么这里就涉及到了多种场景,比如a()调用b():

a()和b()方法中的所有sql需要在同一个事务中吗?

a()和b()方法中的所有sql需要在同一个事务中吗?

a()需要在事务中执行,b()还需要在事务中执行吗?

或者其他情况

这种情况下就要求Spring事务能支持上面各种场景,这就是Spring事务传播机制的由来。

那Spring事务传播机制是如何实现的呢?

先描述其中一个场景中情况,a()在一个事务中执行,调用b()方法时需要新开一个事务执行:

代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a

将数据库连接a的autocommit改为false

把数据库连接a设置到ThreadLocal中

执行a()方法中的sql

执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)

a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交

关于步骤5的一些详细解释:

1、代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线程其实已经拥有一个Spring事务了,则进行挂起

2、挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象中

3、挂起完成后,再次利用事务管理器新建一个数据库连接b

4、将数据库连接b的autocommit改为false

5、把数据库连接b设置到ThreadLocal中

6、执行b()方法中的sql

7、b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交

8、提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中

过程中最为重要的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

————————————————

版权声明:本文为CSDN博主「填丶涂」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.NET/weixin_51423778/article/details/128226788

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>