Spring事务原理,看完这篇你就明白了

您所在的位置:网站首页 spring事务原理和实现机制 Spring事务原理,看完这篇你就明白了

Spring事务原理,看完这篇你就明白了

2023-09-02 07:39| 来源: 网络整理| 查看: 265

Spring事务定义

我正在参与掘金新人创作活动,一起开启写作之路。

来自官方的定义:事务是一系列的数据库操作的集合,这些操作应该要不全部成功,要不全部失效,事务管理是关系型数据库确保数据的完整性和一致性的方法,其核心思想可以概况为ACID

Atomicity(原子性)一个事务应该被视为一个单一的操作单元,这意味着整个操作序   列要么是成功的,要么是不成功的。 Consistency(一致性)这表示数据库的引用完整性、表中唯一的主键等的一致性 Isolation(隔离性)可能会使用相同的数据集同时进行许多事务处理。每个事务都应该与其他事务隔离,以防止数据损坏 Durability(持久性)一旦事务完成,此事务的结果必须成为永久的,由于系统故障无法从数据库中删除 Spring事务原理

当我们了解完Spring事务定义后,我们可以猜想一下究竟Spring是怎么帮我们完成事务的,众所周知,我们要执行事务,只需要开启事务(注解开启/配置文件开启),然后添加@Transactional注解在类或者方法上面,就可以执行事务了,那么Spring究竟是如何完成这个过程的呢?带着疑问,我先来给大家说一下大概原理,如下图

image.png

如图所示,从宏观来说,Spring做的事情无非就是利用事务管理器创建了数据库连接,然后关闭自动提交,再执行我们的业务逻辑,最后提交或者回滚,讲到这里,有经验的童鞋想必已经明白是怎么肥事了,是的没错,它是利用了Spring的AOP,那么具体是怎么做的,下面我就来讲解一下

  我们先从Spring事务配置开始说起,下面主要说的是通过注解的方式

@EnableTransactionManagement @Transaction @EnableTransactionManagement工作原理

SpringBoot项目上通过此注解开启事务AOP

@SpringBootApplication @MapperScan("com.test.transaction.mapper") @EnableTransactionManagement public class TransactionApplication { public static void main(String[] args) { SpringApplication.run(TransactionApplication.class, args); } }

点击进入EnableTransactionManagement

@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import({TransactionManagementConfigurationSelector.class}) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default 2147483647; }

上图可以看到此注解里面有三个属性,proxyTargerClass 实际上是决定它使用什么代理方式,false是使用jdk动态代理,true则使用CGLIB代理,但这个不是本章节主要说的内容,所以不深入探究,第二个是mode()默认为proxy,稍后会用的上,第三个order顾名思义就是一个执行顺序,除此之外,我们可以看到上面有个Import注解,这个注解主要是用于将类注册到Spring IOC容器中,那么我们看看它将什么类往Spring容器中进行了注册

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector { public TransactionManagementConfigurationSelector() { } protected String[] selectImports(AdviceMode adviceMode) { switch(adviceMode) { case PROXY: return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[]{this.determineTransactionAspectClass()}; default: return null; } } }

上面可以看到,对adviceMode进行了判断,而事务的默认是proxy,所以事务往Spring容器中注册了AutoProxyRegistrar和ProxyTransactionManagementConfiguration两个类,那么这两个类分别有什么作用呢?用下图作了一个概括

EnableTransactionManagement.png

简单来说,AutoProxyRegistrar顾名思义就是开启了AOP代理 而ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor就是一个切面 AnnotationTransactionAttributeSource:相当于Pointcut TransactionInterceptor:相当于中的 Advice,事务的拦截方法

AnnotationTransactionAttributeSource就是用来判断某个类上是否存在@Transactional注解, 或者判断某个方法上是否存在@Transactional注解的。

TransactionInterceptor就是代理逻辑,当某个类中存在@Transactional注解时,到时就产生一个 代理对象作为Bean,代理对象在执行某个方法时,最终就会进入到TransactionInterceptor的 invoke()方法。

一句话总结:EnableTransactionManagement注解是用来开启事务aop的,@Transactional就是切点,有这个注解的类都会被代理

Spring事务执行原理

通过上面的分析我们可以对Spring事务有一个基本的了解,那么接下来,我们再通过源码来看看Spring事务执行的时候究竟做了什么事情(因为源码太多,本文仅挑选部分源码来进行解析,感兴趣的童鞋可以私底下继续研究源码)

首先我们来理一下Spring事务创建的整体流程:启动阶段:

Spring创建完bean后会调用applyBeanPostProcessorsAfterInitialization getAdvicesAndXXForBean 判断这个bean是否需要AOP 寻找方法或类上面的@Transcational然后生成代理对象\ computeTransactionAttribute会解析注解包装成TransactionAttrbute对象

方法执行阶段:

1.代理对象CglibAopProxy 执行事务拦截类 TransactionInterceptor的invoke方法

2.获取此类的注解属性然后调用determineTransactionManager看是否需要创建事务管理器,如果没有指定则使用默认的事务管理器

TransactionAttributeSource tas =this.getTransactionAttributeSource();  TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null; TransactionManager tm = this.determineTransactionManager(txAttr);

3.调用createTransactionIfNecessary创建事务

TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

4.使用事务管理器tm去创建一个事务连接

TransactionStatus status = null; if (txAttr != null) { if (tm != null) { status = tm.getTransaction((TransactionDefinition)txAttr); } else if (this.logger.isDebugEnabled()) { this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured"); } }

5.通过 doGetConnection去创建事务,通过 getResource返回一个ConnectionHolder对象,

这个对象很关键,是通过线程的ThreadLocalMap来获取,也就是说我们的事务连接实际上是存在线程变量里面的,如果没有则创建并放入ThreadLocalMap,那么这里其实就可以和我们的传播机制结合起来,如是同一个事务的话则会用这里的事务

protected Object doGetTransaction() { DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject(); txObject.setSavepointAllowed(this.isNestedTransactionAllowed()); ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource()); txObject.setConnectionHolder(conHolder, false); return txObject; }

6.事务创建完成后返回一个TransactionStatu对象,再通过prepareTransactionInfo将事务绑定到线程上,至此,事务已经创建完成

protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) { TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification); if (txAttr != null) { if (this.logger.isTraceEnabled()) { this.logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]"); } ​ txInfo.newTransactionStatus(status); } else if (this.logger.isTraceEnabled()) { this.logger.trace("No need to create transaction for [" + joinpointIdentification + "]: This method is not transactional."); } ​ txInfo.bindToThread(); return txInfo; }

7.后续则是获取此事务链接进行相应的数据库增删查改操作.

本章小结:本章主要是将Spring事务大概原理以及创建过程介绍了一遍,意犹未尽的童鞋可以去继续研究源码,而下个章节我会主要说一下Spring的传播机制,以及相关案例分析,相信会对各位小伙伴的工作学习都会带来一些帮助,也可以关注我的个人公众号,里面会有最新的技术分享内容,我是老道,专注框架原理,中间件,并发编程,只做最肝的干货分享,如果那么本章的分享到此结束,欢迎留言探讨



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3