【源码解析】MyBatis的理解

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
日志服务 SLS,月写入数据量 50GB 1个月
简介: MyBatis 了解多少? MyBatis中n种设计模式的使用?MyBatis 工作原理? 动态 SQL 语句解析? 映射机制? 一二级缓存?

【总】简述下MyBatis 的三层架构以及其中各个模块的核心功能,从基础支撑层到核心处理层,再到暴露给调用的接口层。

【分】然后再深入剖析,MyBatis中n种设计模式的使用;MyBatis 工作原理和运行流程 ;动态 SQL 语句解析;映射机制; 一二级缓存;

文章较长,建议收藏】
Mybatis系列文章:

【源码解析】谈谈你对 MyBatis工作原理 的理解 : MyBatis 工作流程源码解析

【源码解析】谈谈你对 MyBatis动态SQL 的理解:Mybatis动态sql源码解析及动态sql的执行原理

【源码解析】谈谈你对 MyBatis结果集映射和参数绑定 的理解:MyBatis结果集映射源码解析,详细分析了 handleRowValuesForSimpleResultMap() 等方法实现映射的核心步骤

MyBatis 整体架构解析

image.gif编辑

MyBatis架构图主要分三层。基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理  等。它主要的目的是根据调用的请求完成一次数据库操作。API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。

下面对基础支撑层、数据处理层、API接口层一一简述:

基础支撑层

MyBatis 基础支撑层 按照这些单一的能力可以划分为上图所示的九个基础模块。

       第一个,类型转换模块。 在 mybatis-config.xml 配置文件中通过 <typeAliase> 标签为一个类定义别名,这里用到的“别名机制”就是由 MyBatis 基础支撑层中的类型转换模块实现的。类型转换模块还实现了 MyBatis 中 JDBC 类型与 Java 类型之间的相互转换,在 SQL 模板绑定用户传入实参的场景中,类型转换模块会将 Java 类型数据转换成 JDBC 类型数据;在将 ResultSet 映射成结果对象的时候,类型转换模块会将 JDBC 类型数据转换成 Java 类型数据。

image.gif编辑

       第二个,日志模块。 MyBatis 提供了日志模块来集成 Java 生态中的第三方日志框架,该模块目前可以集成 Log4j、Log4j2、slf4j 等优秀的日志框架。

       第三个,反射工具模块。 MyBatis 的反射工具箱是在 Java 反射的基础之上进行的一层封装,为上层使用方提供更加灵活、方便的 API 接口。

       第四个,Binding 模块。 MyBatis 无须编写 Mapper 接口的具体实现,而是利用 Binding 模块自动生成 Mapper 接口的动态代理对象。

       第五个,数据源模块。 MyBatis 自身提供了数据源实现,也是 MyBatis 的默认实现。

       第六个,缓存模块。MyBatis 提供在此提供一级缓存和二级缓存。

       第七个,解析器模块。MyBatis 中有两大部分配置文件需要解析,一个是 mybatis-config.xml 配置文件,另一个是 Mapper.xml 配置文件。这两个文件都是由 MyBatis 的解析器模块进行解析的,其中主要是依赖 XPath 实现 XML 配置文件以及各类表达式的高效解析。

       第八个,事务管理模块。 MyBatis 对数据库中的事务进行了一层简单的抽象,提供了简单易用的事务接口和实现。一般情况下,Java 项目都会集成 Spring,并由 Spring 框架管理事务。

       第九个,资源加载模块。提供了 Resources工具类,内部封装了 ClassLoaderWrapper 类的静态字段,Resources 提供的方法都是在 ClassLoaderWrapper 对象中实现的。加载配置文件用。

核心处理层

核心处理层是 MyBatis 核心实现所在,其中涉及就是 MyBatis 的初始化以及执行一条 SQL 语句的全流程

第一个,配置解析。 MyBatis 有三处可以添加配置信息的地方,分别是:mybatis-config.xml 配置文件、Mapper.xml 配置文件以及 Mapper 接口中的注解信息。在 MyBatis 初始化过程中,会加载这些配置信息,并将解析之后得到的配置对象保存到 Configuration 对象中。例如使用的 <resultMap> 标签(也就是自定义的查询结果集映射规则)会被解析成 ResultMap 对象。我们可以利用得到的 Configuration 对象创建 SqlSessionFactory 对象(也就是创建 SqlSession 对象的工厂对象),之后即可创建 SqlSession 对象执行数据库操作了。

第二个,SQL 解析与 scripting 模块。MyBatis 提供的动态 SQL 标签非常丰富,包括 <where> 标签、<if> 标签、<foreach> 标签、<set> 标签等。MyBatis 中的 scripting 模块负责动态生成 SQL 的核心模块。会根据运行时用户传入的实参,解析动态 SQL 中的标签,并形成 SQL 模板,然后处理 SQL 模板中的占位符,用运行时的实参填充占位符,得到数据库真正可执行的 SQL 语句。

第三个,SQL 执行。 在 MyBatis 中,要执行一条 SQL 语句,会涉及非常多的组件,比较核心的有:Executor、StatementHandler、ParameterHandler 和 ResultSetHandler。其中,Executor 会调用事务管理模块实现事务的相关控制,同时会通过缓存模块管理一级缓存和二级缓存。SQL 语句的真正执行将会由 StatementHandler 实现。StatementHandler 会先依赖 ParameterHandler 进行 SQL 模板的实参绑定,然后由 java.sql.Statement 对象将 SQL 语句以及绑定好的实参传到数据库执行,从数据库中拿到 ResultSet,最后,由 ResultSetHandler 将 ResultSet 映射成 Java 对象返回给调用方,这就是 SQL 执行模块的核心。

image.gif编辑

接口层

接口层是 MyBatis 暴露给调用的接口集合,如 SqlSession 接口、SqlSessionFactory 接口等。其中,最核心的是 SqlSession 接口获取 Mapper 代理、执行 SQL 语句、控制事务开关等。

此时我们已经把 MyBatis 的三层架构以及其中各个模块的核心功能都阐述完毕,下面可以展开设计模式和MyBatis启动流程等。

MyBatis中的设计模式的使用

       MyBatis 的整体架构符合外观模式(Facade Pattern)的。日志模块是一个典型的使用适配器模式的场景适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作;优先加载日志组件,以及实现插件时,使用动态代理(Proxy Pattern),给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用;数据源模块重点讲解数据源的创建和数据库连接池的源码分析;数据源创建比较复杂,对于复杂对象的创建,使用工厂模式(Factory Pattern);在 MyBatis 处理动态 SQL 语句的时候,会将动态 SQL 标签解析为 SqlNode 对象,多个 SqlNode 对象就是通过组合模式(Composite Pattern)组成树形结构供上层使用的。

       MyBatis 缓存模块是一个经典的使用装饰器模式(Decorator Pattern)实现的模块,类图如下:Cache 接口是缓存模块的核心接口,定义了缓存的基本操作;PerpetualCache在缓存模块中扮演ConcreteComponent 角色,使用HashMap 来实现 cache 的相关操作;BlockingCache:阻塞版本的缓存装饰器,保证只有一个线程到数据库去查找指定的 key 对应的数据,缓存模块如下图

image.gif编辑

       如下图,配置加载阶段大量的使用了建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。BaseBuilder:所有解析器的父类,包含配置文件实例,为解析文件提供的通用的方法;XMLConfigBuilder: 主要负责解析 mybatis-config.xml;XMLMapperBuilder: 主要负责解析映射配置 Mapper.xml 文件;XMLStatementBuilder: 主要负责解析映射配置文件中的 SQL 节点;image.gif编辑

       SqlSessionFactory 使 用 工厂模式(Factory Pattern) 创建 SqlSession , 其默认的实现类DefaultSqlSessionFactory , 其中获取 SqlSession 的 核 心 方 法 openSessionFromDataSource(),在这个方法中从 configuration 中 获 取 的 TransactionFactory 是 典 型 的 策 略 模 式(Strategy Pattern) 的 应 用 。 运 行 期 ,TransactionFactory 接口的实现,是由配置文件配置决定的,可配置选项包括:JDBC、Managed, 可根据需求灵活的替换 TransactionFactory 的实现;

       Executor如下图: 定义了数据库操作最基本的方法;CacheingExecutor:使用装饰器模式(Decorator Pattern),对真正提供数据库查询的 Executor 增强了二级缓存的能力 ; 二级缓存 初始化位置 :DefaultSqlSessionFactory.openSessionFromDataSource();BaseExecutor:抽象类,实现了 executor 接口的大部分方法,主要提供了缓存管理和事务管理的能力,其他子类需要实现的抽象方法为:doUpdate,doQuery 等方法;BatchExecutor: 批量执行所有更新语句,基于 jdbc 的 batch 操作实现批处理;SimpleExecutor: 默认执行器,每次执行都会创建一个statement,用完后关闭。;ReuseExecutor: 可重用执行器,将 statement 存入 map 中,操作 map 中的 statement 而不会重复创建 statement;

       BaseExecutor 、BaseStatementHandler 模板模式(Template Pattern);BaseExecutor 执行器抽象类,实现了 executor接口的大部分方法,主要提供了缓存管理和事务管理的能力,其他子类需要实现的抽象方法为:doUpdate,doQuery 等方法;

image.gif编辑

MyBatis 工作原理(运行流程)

【总】可以把 MyBatis 的运行流程分为三大阶段:

1. 初始化阶段:读取 XML 配置文件和注解中的配置信息,创建配置对象,并完成各个模块的初始化的工作;

2. 代理封装阶段:封装 iBatis 的编程模型,使用 mapper 接口开发的初始化工作;

3. 数据访问阶段:通过 SqlSession 完成 SQL 的解析,参数的映射、SQL 的执行、结果的解析过程;

MyBatis 工作流程

image.gif编辑

       (1)读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。

       (2)加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

       (3)构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。

       (4)创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。

       (5)Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。

       (6)MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。

       (7)输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。

       (8)输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。

MyBatis 工作流程源码分析

这部分我们要知道 MyBatis 初始化流程源码,MyBatis是如何加载配置文件的? Mapper.xml 映射文件是如何解析的? SQL 语句是如何解析<select><insert><delete><update> 等 SQL 语句标签)

防止文章过长,在收藏夹吃灰,这里分成多篇文章
详细连接:
【万字源码解析】谈谈你对 MyBatis工作原理 的理解【深度好文 建议收藏】

动态 SQL 语句解析

这部分我们要知道Mybatis动态sql是做什么的?都有哪些动态sql?动态sql的执行原理?

防止文章过长,在收藏夹吃灰,这里分成多篇文章
详细连接:
【源码解析】谈谈你对 MyBatis动态SQL 的理解【建议收藏】

结果集映射解析

这部分我们要知道 MyBatis 如何进行 参数绑定、SQL 执行和结果映射的?

防止文章过长,在收藏夹吃灰,这里分成多篇文章
详细连接:

【源码解析】谈谈你对 MyBatis结果集映射和参数绑定 的理解_FMC_WBL的博客-CSDN博客

相关文章
|
23天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
64 2
|
24天前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
1月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
47 3
|
2月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
59 5
|
2月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
135 5
|
2月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
2月前
|
算法 Java 程序员
Map - TreeSet & TreeMap 源码解析
Map - TreeSet & TreeMap 源码解析
38 0
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
72 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0
|
2月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
64 0

推荐镜像

更多