spring事务的源码解析

499 阅读4分钟

前言

今天来翻看一下事务的源码,看下spring是如何对事务进行处理的。

在研究事务的源码之前,我们先回顾下事务是啥,有什么特性。

众所周知,事务就是用来确保方法能完整的执行。如果发生了异常,那么在发生异常之前进行的数据库操作能够回滚掉,这是为了确保数据的一致性。

事务的四大特性:

一致性
隔离性
持久性
原子性

一致性:就是如果有多个数据库操作,要么都成功,要么都失败。

隔离性:多个线程来执行事务方法的时候,能够相互不影响,具体的隔离类型是由事务的隔离级别来决定。

持久性:一旦事务成功的执行了,这个数据库操作成功提交了,接下来的操作或者故障不能对这个数据有影响了。

原子性:原子,顾名思义就是最微小的单位了,原子性就是把这个事务内的所有数据库操作认为是同一个不可再分对象,其所有数据库操作要么全部成功要么全部失败(因为他们是一体的嘛,不能再切分了)

事务的传播机制

事务的传播机制是在@Transaction这个注解内定义的,由参数 propagation决定的,总共有七种传播机制:

图片.png

事务的隔离级别

事务还有四大隔离级别,和数据库的隔离级别一样:

读未提交

读已提交

可重复读

序列化

事务的使用

那么既然我们对事务的基本概念有了个基本的了解,那么就看一下如何使用吧。

通常在我们的项目里面如果想要开启事务的话,那么就需要在配置文件里面创建一个事务管理器,去管理我们的目标数据源。

然后再添加上开启事务的注解:@EnableTransactionManagement 这个注解就相当于事务的开关了。那么我们当然就从事务的开关进去看看,开关后面做了些什么。

图片.png

一个平平无奇的注解,但是, 他加了一个Import注解,那么他这个注解就变得不同寻常了。 我们知道,这个Import注解就是起到一个导入方法的作用。那么导入这个方法是干啥的呢? 我们再进去看下

图片.png

内容很简单,根据AdviceMode去创建不同的数组,一般我们使用事务都是用的默认代理的方式,那么就会走第一个Proxy,创建两个组件

AutoProxyRegistrar.class
ProxyTransactionManagementConfiguration.class

AutoProxyRegistrar

那我们先看第一个组件内容:

图片.png

通过工具类把自动代理组件给注册到容器中

图片.png

InfrastructureAdvisorAutoProxyCreator

这个组件,根据名称可以看出是一个自动代理增强器,我们看下他的类以及他的父类都是什么

图片.png

继续看他的父类

图片.png

看到这个PostProcessor我们就可以判断这是一个后置处理器。就是我们在创建完对象的时候通过后置处理器来对对象进行包装,包装成一个代理对象

图片.png

图片.png

要知道事务实际上是通过代理的方式来对目标对象进行处理。因为我们知道,如果在方法内如果把异常给catch掉,那么即使发生异常,他也是不会回滚的。因为目标方法已经把异常给处理掉了,代理对象就不会捕获到这个异常,因此事务内部就不会对他进行回滚操作,那么这个事务就失效了。

可以简化为:

try {
    // 目标方法
    proxyTarget();
} catch (Exception e) {
    // 如果发生异常,回滚
    rollback();
}
// 如果正常执行,提交
commit();   

ProxyTransactionManagementConfiguration

来看第二个组件

图片.png

按照我标注的顺序,他创建了三个bean,

第一个bean:

根据名称,我们可以判断这个是一个处理注解的bean

图片.png

图片.png

解析@Transaction这个注解里面的属性。

那么第一个bean的作用就是解析并读取注解的内容

第二个bean:

图片.png

图片.png

这个类实现了方法拦截器接口, 会不会就是把目标方法拦截下来然后对他进行事务控制呢? 我们看他的invoke方法

图片.png

图片.png

果不其然,这里就是事务操作的核心,获取到事务管理器,执行目标方法,提交/回滚事务。

第三个bean:

把前面两个bean内容注册到事务管理增强器并返回。

总结

事务的本质其实还是通过代理的方式对目标方法进行增强处理。通过后置处理器注册代理对象,到包装代理对象,把代理对象注册到容器中,通过方法拦截器获取事务管理器,通过事务管理器对方法进行事务处理,提交或者回滚事务。

简单描述的话几句话就叙述完了,但其内部的实现原理十分复杂,值得我们花费时间去细细钻研。

才疏学浅,难免会有疏漏。如果各位小伙伴发现哪里有不对的地方,欢迎指正,一起进步。