读书笔记-《Spring技术内幕》(四)事务

前面我们依次学习了 IoC、AOP、MVC(读书笔记-《Spring技术内幕》(一)IoC容器的实现读书笔记-《Spring技术内幕》(二)AOP的实现读书笔记-《Spring技术内幕》(三)MVC与Web环境),已经涵盖了 Spring 最核心的内容。

今天,我们再来研究一个比较常用的组件------事务,然后这本书的读书笔记就可以完结了~


01

Spring 事务概述

按照惯例,我们先从程序员的视角出发,看看 Spring 帮我们做了什么,再学习其具体的设计与实现。

在没有使用 Spring 的 JavaWeb 项目中,是怎么实现事务的呢?请看下面的示例代码:

java 复制代码
public void hello {
    Connection conn = openConnection();
    try {
        conn.setAutoCommit(false);
        // 业务代码
        conn.commit();
    } catch (SQLException e) {
        conn.rollback();
    } finally {
        conn.setAutoCommit(true);
        conn.close();
    }
}

这个 Connection 我印象很深,初学时因为它学习到了第一个设计模式------单例模式,这个模式的懒汉/饿汉实现、双重检测是早期常见的面试题。(跑题了,赶紧拉回来......)

简单来说,这里的代码直接操作数据库连接,并且将事务处理代码和业务代码耦合,非常糟糕。

而在 Spring 的帮助下,我们只需要一行注解,就很优雅。

java 复制代码
@Transactional
public void world {
    // 业务代码
}

看到这种将非业务功能代码解耦出来,并通过注解(声明式)实现功能的操作,很容易猜到,其原理是通过 AOP 将事务处理的功能编织进来,本质上可以看作是一个基于 Spring IoC、AOP 的优秀应用。 (注意:后面默认指代的是声明式使用,Spring 事务也可以编程式使用,其实现非常简单,不涉及框架特性,但是会耦合业务代码,本文不做讲述)

既然如此,从流程上看 Spring 事务的实现就有两个重点

  • 如何读取配置,并构造这个代理对象?

  • 这个代理对象如何实现事务的创建、提交、回滚等等?


02

Spring 事务设计概览

在回答上面两个问题之前,我们先看看类层次结构。

简单概括并补充一下:

  • ProxyConfig、FactoryBean 等:为前面 IoC、AOP 模块的设计,不做赘述。

  • **TransactionProxyFactoryBean:**生成代理对象。

  • **TransactionInterceptor:核心类,**对代理方法进行拦截,将事务功能编织进来。

  • **PlatformTransactionManager、AbstractPlatformTransactionManager:**封装底层不同数据库对事务的实现,如生成、提交、回滚、挂起等。

  • **TransactionAttribute:**事务配置信息在 Spring 中的抽象。

  • **TransactionInfo:**事务信息抽象,包含事务和 TransactionStatus。


    03

    构建代理对象

​​​​​​​​​​​​​​

​​​​​​​****

构建代理对象的时序图如上所示,用文字概括一下:

  • 在 IoC 容器完成 Bean 的依赖注入时,通过 initializeBean() 调用 createMainInterceptor(),创建一个 TransactionAttributePointcut,为读取 TransactionAttribute 做准备。

  • 由于 AbstractSingletonProxyFactoryBean 实现了 InitializingBean 接口,在 afterPropertiesSet() 中会实例化 ProxyFactory,设置通知、目标对象,最终返回代理对象。

  • 在构建好代理对象后,调用代理方法时便会调用相应的 TransactionInterceptor,匹配对应的配置。(举个例子的话可以看看 NameMatchTransactionAttributeSource,其通过成员变量 nameMap 的维护来实现名称匹配)


04

****处理事务

构建好代理对象后,对原方法的调用就会被拦截,也就是进入 TransactionInterceptor 的 invoke()。其会依次获取事务处理配置、PlatformTransactionManager,并交由这个具体的处理器来实现事务的创建、提交、回滚等等。

这里我们就以事务的创建为例,看看 TransactionAspectSupport 的 createTransactionIfNecessary 方法的时序图。

这里就两点可以留意下:

  • 针对不同的事务传播机制,源码里有各种条件分支。(不过在实际工作中,我还没使用过非默认的传播机制,一般是通过 MQ 来保障最终一致性)

  • bindToThread() 是通过 TransactionAspectSupport 的成员变量 ThreadLocal<TransactionInfo> transactionInfoHolder 实现,其也体现了事务的隔离性。

至此,我们只需再进一步就可抵达终点了。

前面的类层次结构图有提到 AbstractPlatformTransactionManager,其定义了事务的生成、提交、回滚、挂起,对于不同的数据库有不同的实现。

以 DataSourceTransactionManager 为例,点开它的源码一看,我们就会发现非常眼熟。它就和一开始我们写的示例代码类似,直接操作 Connection,打印日志等等。


​​​​​​​

原文链接读书笔记-《Spring技术内幕》(四)事务

原创不易,点个关注不迷路哟,谢谢~

文章推荐:

相关推荐
陈小桔2 分钟前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!3 分钟前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg367815 分钟前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July31 分钟前
Hikari连接池
java
微风粼粼42 分钟前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse
番茄Salad43 分钟前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud
立志成为大牛的小牛1 小时前
数据结构——二十六、邻接表(王道408)
开发语言·数据结构·c++·学习·程序人生
天若有情6731 小时前
Spring MVC文件上传与下载全面详解:从原理到实战
java·spring·mvc·springmvc·javaee·multipart
祈祷苍天赐我java之术1 小时前
Redis 数据类型与使用场景
java·开发语言·前端·redis·分布式·spring·bootstrap
XiangrongZ1 小时前
江协科技STM32课程笔记(五)— ADC模数转换器
笔记·科技·stm32