架构总览
本文将详细介绍 MyBatis 的整体架构,包括 io、binding、session、reflection 等主要模块。同时,阐述了 MyBatis 代码的包结构及各组件在执行 SQL 时的运作流程。
核心模块概览
MyBatis 源码包含以下模块:
annotations --- 注解相关
binding --- 代理类生成相关
builder --- 构造器模块
cache --- 缓存相关,用于实现一级、二级缓存
cursor --- 数据游标
datasource --- 数据源模块
exceptions --- 异常模块
executor --- 执行器模块
io --- 配置文件 I/O
jdbc --- 与 JDBC 交互的中间层
lang --- JDK 版本注解
logging --- 日志模块
mapping --- 映射模块,负责保存每条 SQL 需要的各种信息
parsing --- 解析器模块
plugin --- 扩展插件模块
reflection --- 反射工具模块
scripting --- 动态 SQL 生成模块
session --- 会话模块,核心
transaction --- 简易事务管理器
type --- 类型转换模块
util --- 工具类
其中主要模块的详细功能如下。
session 模块
Session(会话)模块是 MyBatis 与用户交互的核心,内部包含我们最为熟悉的 SqlSession
和 SqlSessionFactory
接口。最核心的接口是 SqlSession
,通过它我们可以实现许多功能,例如获取 Mapper
代理、执行 SQL 语句以及控制事务等。
mapping 模块
Mapping 模块是 MyBatis 的核心,每条 SQL 语句都会被封装为一个 MappedStatement
对象。MappedStatement
包含了执行 SQL 所需的各种信息,主要包括以下几个方面:
- SQL 语句定义:存储并管理映射的 SQL 语句,可以是静态的 SQL,也可以是动态 SQL。
- 参数映射:定义输入参数的类型及其在 SQL 语句中的位置。
- 结果映射:定义 SQL 查询结果与 Java 对象之间的映射关系。
- 缓存配置:支持对查询结果的缓存,提供一级和二级缓存配置。
- 执行配置:包含执行 SQL 语句时的各种配置,如超时时间、执行模式(如查询、插入、更新、删除)等。
io 模块
该模块通过 I/O 流将配置文件加载到内存,比较简单这里略过了。
type 模块
Type 模块用于完成 JDBC 类型与 Java 类型之间的相互转换:
![MyBatis 类型转换](images/jdbc-java-type.webp)
- 在 SQL 模板绑定用户传入实参的场景中,类型转换模块会将 Java 类型数据转换成 JDBC 类型数据;
- 在将结果集映射成结果对象的时候,类型转换模块会将 JDBC 类型数据转换成 Java 类型数据。
此外,该模块还实现了 typeAliases
别名机制。
logging 模块
MyBatis 通过 logging 模块来集成 Java 生态中的第三方日志框架,该模块目前可以集成 Log4j、Log4j2、slf4j 等优秀的日志框架。
reflection 模块
MyBatis 的 reflection 模块对 Java 反射机制进行了封装,为上层应用提供了更加灵活、方便的 API 接口。同时,它缓存了与 Java 反射相关的元数据,提升了反射代码执行的效率,优化了反射操作的性能。
binding 模块
Binding 模块用于生成 mapper 接口的代理实现。我们可以通过 SqlSession
获取 Mapper
接口的代理,并通过该代理执行关联的 mapper.xml 文件中的数据库操作。
datasource 模块
MyBatis 的 datasource 模块负责管理和提供数据库连接,提供了数据源的配置、管理以及与数据库的交互功能。
cache 模块
数据库是生产中最核心的组件,很多业务数据都会落地到数据库,所以数据库性能的优劣直接影响了上层业务系统的优劣。我们很多线上业务都是读多写少的场景,在数据库遇到瓶颈时,缓存是最有效、最常用的手段之一,正确使用缓存可以将一部分数据库请求拦截在缓存这一层,这就能够减少一部分数据库的压力,提高系统性能。
MyBatis 的一级缓存和二级缓存实现都依赖该模块。
parsing 模块
Parsing 模块用于解析 MyBatis 的 核心配置文件 和 映射配置文件。
transaction 模块
MyBatis 对数据库中的事务进行了一层简单的抽象,提供了简单易用的事务接口和实现。
不过现代 Java 项目往往会集成 Spring,并由 Spring 框架管理事务,因此一般我们会将 MyBatis 事务接口的实现委托给 Spring。
scripting 模块
动态 SQL 功能是 MyBatis 的一大亮点,只需使用 MyBatis 提供的标签,即可根据实际的运行条件动态生成要执行的 SQL 语句。MyBatis 提供了丰富的动态 SQL 标签,包括 <where>
标签、<if>
标签、<foreach>
标签、<set>
标签等。
MyBatis 通过 scripting 模块动态生成 SQL。它会根据运行时用户传入的实参,解析动态 SQL 中的标签,并形成 SQL 模板,然后处理 SQL 模板中的占位符,用运行时的实参填充占位符,得到数据库真正可执行的 SQL 语句。
Executor 模块
Executor 模块是 MyBatis 的另一个核心,涉及非常多的组件,主要有 Executor
、StatementHandler
、ParameterHandler
和 ResultSetHandler
等:
Executor
负责 SQL 动态语句的生成,同时会通过缓存模块管理一级缓存和二级缓存。- SQL 语句的真正执行将会由
StatementHandler
实现。StatementHandler
会先依赖ParameterHandler
进行 SQL 模板的实参绑定。 - 然后通过 JDBC 中的
java.sql.Statement
将 SQL 语句以及绑定好的实参传到数据库执行。 - 最后,从数据库中拿到
ResultSet
,并由ResultSetHandler
将ResultSet
映射成 Java 对象返回给调用方。
plugin 模块
很多成熟的开源框架,都会以各种方式提供扩展能力。当框架原生能力不能满足某些场景的时候,就可以针对这些场景实现一些插件来满足需求,这样的框架才能有足够的生命力。
核心组件概览
了解了 MyBatis 的核心模块,下面我们再来了解一下执行过程中涉及的核心组件:
+---------------------------------------+ +-----------------+
| SqlSession | | Configuration +-------+
+---+-----------------------------------+ +-----------------+ |
| ^ |
v | |
+-----------------------------------+---+ |
| Executor | |
+---+-----------------------------------+ |
| ^ +----------+ |
v | +-| BoundSql | |
+-----------------------------------+---+ | +----------+ |
| StatementHandler +-| |
+-++------------------------------------+ | +-----------------------+ |
|| ^ +-| MappedStatement +-+
|| | |-----------------------|
|v | | SqlSource & ResultMap |
+-|----------------+ +---------------+--+ +-----------------------+
| ParameterHandler | | ResultSetHandler |
+-|------------+---+ +--^-----^---------+
| | | |
| +---v--------+---+ |
| | TypeHandler<T> | |
| +-+--------^-----+ |
| | | |
+-|----------|--------|-------|---------+
| | | +---+-------+ JDBC|
| | | | ResultSet | |
| | | +--------^--+ |
| | | | |
| v----------v-------------+------+ |
| | Statement | |
| | +------------------+ +-------+| |
| | | PrepareStatement | | ... || |
| | +------------------+ +-------+| |
| +-------------------------------+ |
+---------------------------------------+
- MyBatis 通过会话机制执行 SQL,顶层接口为
SqlSession
; Executor
执行器是 MyBatis 的核心,它负责动态 SQL 的生成,和查询缓存的维护;StatementHandler
负责与 JDBC 交互,包括对Statement
设置参数,以及将 JDBC 返回的 ResultSet 封装为 List。