读书笔记-《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技术内幕》(四)事务

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

文章推荐:

相关推荐
文艺理科生7 分钟前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling7 分钟前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
南极企鹅9 分钟前
springBoot项目有几个端口
java·spring boot·后端
Luke君6079711 分钟前
Spring Flux方法总结
后端
define952715 分钟前
高版本 MySQL 驱动的 DNS 陷阱
后端
清风拂山岗 明月照大江15 分钟前
Redis笔记汇总
java·redis·缓存
承渊政道16 分钟前
Linux系统学习【Linux系统的进度条实现、版本控制器git和调试器gdb介绍】
linux·开发语言·笔记·git·学习·gitee
lpfasd12321 分钟前
两个美国:精英的知识崇拜与底层的反智驯化
笔记
清水迎朝阳22 分钟前
解锁读书新体验--有声小说书屋 本地网站的 标注笔记功能
笔记·电子书·读书·标注·有声小说
xiaoxue..30 分钟前
合并两个升序链表 与 合并k个升序链表
java·javascript·数据结构·链表·面试