核心功能拆解 工作流程
MyBatis 是一个 Java 的 ORM 框架,它使用 XML 或注解来配置和映射 SQL 语句,同时提供了增删改查等常用操作的 API。Mybatis 还提供了许多高级映射和查询功能,例如延迟加载、缓存和批量操作,这使得开发人员可以轻松地编写出高性能、可维护的数据访问层。
关于 MyBatis 我们主要要了解他的工作流程,特性,和部分重要的知识点,就像 Spring,我们主要是了解他的生命周期,可扩展项等,所谓生命周期,也是 Spring 的工作流程。
以下是整个 MyBatis 的工作流程图,对应图中会讲解每个节点重要的知识点。这里要记住 MyBatis 主要的工作模式就是解析、准备和执行,所谓解析就是得到 XML 的信息,维护到一个叫 Configuration
的配置类中;准备就是 opensession
部分,他会得到 Configuration
中的信息,根据执行部分所使用的执行器,数据源,事务等进行实例化和关系映射;使用就是当我们去进行查询或新增等操作,从资源和信息中拿取已被缓存的对象或执行器等,执行对应的方法。
# 解析
解析部分对应图中 加载&解析XML
至 XMLConfigBuilder#mapperElement
这里,可以说是读取 XML 到维护各类对象关系和信息的核心。下面我们分解讲解每个步骤都做了哪些事情以及核心部分解析得到了什么。
# 加载 & 解析 XML
这部分主要是读取 mybatis-config-datasource.xml
文件,该文件主要维护了一些公共资源信息,包括环境信息(数据库连接信息),对应的 mapper 文件信息,设置信息等。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置信息 -->
<settings>
<!-- 全局缓存:true/false 管理一级缓存和二级缓存的是否使用 -->
<setting name="cacheEnabled" value="true"/>
<!--缓存级别:SESSION/STATEMENT-->
<setting name="localCacheScope" value="STATEMENT"/>
</settings>
<!-- 环境信息 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://10.240.30.93:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="Dev@root2021"/>
</dataSource>
</environment>
</environments>
<!-- 维护所有mapper -->
<mappers>
<!-- XML 配置 -->
<mapper resource="mapper/Activity_Mapper.xml"/>
</mappers>
</configuration>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
读取到文件后调用 XMLConfigBuilder#parse
进行解析,解析内容如下。
# Configuration 初始化配置
在整个文件解析之前,MyBatis 会先把一些信息进行提前初始化,也就是上图中 new Configuration()
阶段,该类最终会被多个 MyBatis 的类所引用并贯穿整个 MyBatis 工作流程,由于被引用的类太多,这里就不一一列举,我们只要知道他贯穿整个流程即可。
Configuration 被初始化时包含了大量的信息,这些信息就是在解析 xml 文件时维护的,逐一讲解下每个配置的具体作用:
- environment:缓存了环境 ID(可设置默认环境,环境包括:开发环境、测试环境等),事务工厂,数据源(有池或无池或其他连接池)等
- mapperRegistry:映射注册机,缓存每个接口(
接口对象Class做为key
)所对应的MapperProxyFactory
,提供添加映射代理类和获取代理类 - mappedStatements:缓存 SQL 语句的拆解信息。XML 的
namespace.标签ID做为(key)
,value 为 MappedStatement,信息包括:mapper路径
,SQL类型(SELECT|INSERT等)
,SQL语句
,条件
,该条语句的缓存信息
,返回结果对象
,是否缓存标志
等。 - resultMaps:缓存 resultMap 标签的拆解信息。XML 的
namespace.resultMap做为(key)
,然后对应 value 存放SQL字段,映射对象字段,字段JAVA数据类型,类型对应的执行器
等 - interceptorChain:缓存 plugins 标签的拆解信息。会在执行
newParameterHandler,newResultSetHandler,newStatementHandler,newExecutor
进行拦截。 - typeAliasRegistry:缓存了每个 java 基本类型的封装类,以及
JdbcTransactionFactory,DruidDataSourceFactory,UnpooledDataSourceFactory,PooledDataSourceFactory,PerpetualCache,FifoCache
等 Mybatis 提供的已知类,用于快速解析 XML 描述的值,便于快速得到 Class 信息并获取实例。 - typeHandlerRegistry:存放对应数据类型的处理策略,比如 JAVA 类型,对应 SQL 类型的处理策略,或 JAVA 类型对应的处理策略。用于设置 SQL 语句参数和获取查询结果的数据类型转换策略。
- objectFactory:对象工厂,用于创建对象实例,使用反射。
- objectWrapperFactory:对象包装器,放着,被解析对象的实例,以及对应的 set,get,构造器,类型等信息。
objectFactory
与objectWrapperFactory
是为MetaObject
提供支持的,以解析对象信息进行,然后获取对象某个特定属性的数据,缓存是为了加快获取速度,如果属性也是一个对象则会递归缓存,获取值也会递归获取。 - loadedResources:存放已被加载的
mapper.xml
文件,以防止重复加载 - languageRegistry:存放默认的语言解析驱动器,比如存放了
XMLLanguageDriver
,提供快速获取这个解析器,然后提供 SQL 解析。 - cacheEnabled:解析是否启用缓存,该配置对于二级缓存生效,一次缓存是默认缓存。
- localCacheScope:一级缓存,缓存策略默认是永久缓存,缓存方式分为
SESSION
和STATEMENT
,SESSION
在该会话中命中相同 sql 语句和条件,若在该SESSION
中发生insert/update/delete/commit/rollback/close
则会清除缓存,但是,并不会影响其它会话中的缓存;STATEMENT
,只针对当前会话执行的这一语句有效,执行完毕查询会立即清除缓存。 - caches:二级缓存,基于
namespace
的缓存,可提供第三方其他方式实现。
# environments 环境解析
在环境解析过程中会得到下面几个重要的属性:
- ID:表明使用哪一个环境做为主要环境配置,解析 XML 中的
<environment >
标签 - TransactionFactory:解析 XML 中的
<transactionManager>
的 type 属性,如果是JDBC
则就是JdbcTransactionFactory
,也可以自行设置,需要自己注册到typeAliasRegistry
中 - DataSourceFactory:解析 XML 中
<dataSource>
的 type 属性,如果是POOLED
,则对应PooledDataSourceFactory
,UNPOOLED
对应UnpooledDataSourceFactory
,DRUID
对应DruidDataSourceFactory
- DataSource:解析 XML 中
<property>
得到具体的连接信息,从DataSourceFactory
中获取DataSource
当以上的信息组件完毕后会封装到 Environment
中,然后添加到 configuration
# mapper 解析
在 mapper 解析中有两种不同的解析,一个是我们常见的 XML 解析,一种是注解,如 @select,这里只讲 XML 解析,有关 @select 等注解解析,放在后续专开一章。那解析首先会读取所到所有的 mapper,在分别解析每个 mapper
<mappers>
<!-- XML 配置 -->
<mapper resource="mapper/Activity_Mapper.xml"/>
</mappers>
2
3
4
一个完整的 Mapper 大致包含如下信息,所以内部会有多个解析分别解析,如 cache 解析,resultMap 解析,select 解析,insert 解析等,我们这里说下重要的解析对象和作用即可。
<mapper namespace="cn.bugstack.mybatis.test.dao.IActivityDao">
<cache eviction="FIFO" flushInterval="600000" size="512" readOnly="true"/>
<resultMap id="activityMap" type="cn.bugstack.mybatis.test.po.Activity">
<id column="id" property="id"/>
<result column="activity_id" property="activityId"/>
<result column="activity_name" property="activityName"/>
<result column="activity_desc" property="activityDesc"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<select id="queryActivityById" parameterType="cn.bugstack.mybatis.test.po.Activity" resultMap="activityMap" flushCache="false" useCache="true">
SELECT activity_id, activity_name, activity_desc, create_time, update_time
FROM activity
<trim prefix="where" prefixOverrides="AND | OR" suffixOverrides="and">
<if test="null != activityId">
activity_id = #{activityId}
</if>
</trim>
</select>
</mapper>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<cache >
标签配置于二级缓存,对于缓存也会有单独的一章讲解,这里只讲解析得到的重要类及作用,通过标签会封装一个 Cache
对象,该对象以 namespace
做为 cache
的 Id
,并把 Cache
对象添加到 configuration
中
<resultMap>
标签配置一个 <select >
标签的 resultMap 属性返回结果对象的关系映射,他会得到对象以及得到描述的各 java 属性类型和对应的 TypeHandler
类型处理器,在返回的时候使用类型处理器,处理查询返回结果的数据类型对应 java 的映射。 <resultMap>
标签可以有多个,所以会添加到集合中,然后维护到 configuration
中
<select> or <insert>
这里最主要的部分就是在解析完成后会把 namespace.id
做为 key
,把解析的信息 MappedStatement
做为 value
,维护到 configuration
中,以便 Mybatis 在被代理类调用方法的时候快速找到,该方法对应的 SQL 信息等