【MyBatis-Plus 源码分析】核心组件、工作流程、SQL执行过程、源码分析
MyBatis-Plus 是一个增强版的 MyBatis 框架,它在 MyBatis 的基础上增加了许多实用的功能,例如乐观锁插件、字段自动填充、分页插件、条件构造器和 SQL 注入器等。MyBatis-Plus 允许开发者无需编写 XML 文件,直接通过继承 BaseMapper 接口的类来完成数据库操作。MyBatis-Plus 作为 MyBatis 的增强框架,其工作流程在继承 MyBati
文章目录
前言
MyBatis-Plus 是一个增强版的 MyBatis 框架,它在 MyBatis 的基础上增加了许多实用的功能,例如乐观锁插件、字段自动填充、分页插件、条件构造器和 SQL 注入器等。MyBatis-Plus 允许开发者无需编写 XML 文件,直接通过继承 BaseMapper 接口的类来完成数据库操作。
第一章:MyBatis-Plus 核心组件与工作流程
MyBatis-Plus 在 MyBatis 的基础上增加了诸多功能,如乐观锁、自动填充字段、分页等。它的核心组件包括 SQL 注入器、主键生成器等,这些组件协同工作,构成了 MyBatis-Plus 的强大功能。
1.1 MyBatis-Plus 与 MyBatis 的关系和优势
对比项 | MyBatis | MyBatis-Plus |
---|---|---|
简介 | 半自动的持久层框架,提供了一系列 API 用于数据库交互 | 增强版 MyBatis 框架,继承所有特性并提供更多便捷功能 |
关系 | 无 | 完全兼容 MyBatis,在其基础上增加更多功能 |
CRUD 操作 | 需要手动编写 SQL 语句和映射 XML | 提供简洁 API,简化 CRUD 操作 |
XML 配置 | 需要编写 XML 文件配置 SQL 映射 | 无需 XML 配置,支持注解或 Java API |
查询构建 | 手动编写 SQL,不支持复杂查询的简化构建 | 提供条件构造器,简化复杂查询条件的构建 |
分页功能 | 需要手动处理分页逻辑 | 内置分页插件,方便实现分页 |
乐观锁 | 不直接支持,需要手动实现 | 支持乐观锁机制,简化并发控制 |
字段自动填充 | 不支持 | 支持字段自动填充,如创建时间、更新时间 |
性能 | 依赖手动优化 SQL 语句 | 性能优化,如 SQL 语句缓存和重用 |
可扩展性 | 高度可扩展,支持自定义插件和拦截器 | 保持高度可扩展性,支持自定义开发 |
开发效率 | 较高,但需要较多手动配置 | 更高,简化了常见操作和配置 |
适用场景 | 适合需要精细控制 SQL 语句的场景 | 适合快速开发,简化数据库操作的场景 |
MyBatis-Plus 作为一个增强版的 MyBatis 框架,它不仅继承了 MyBatis 的所有优点,还在此基础上提供了更多现代化、便捷的功能。对于需要快速开发且希望简化数据库操作的 Java 应用来说,MyBatis-Plus 是一个非常优秀的选择。
1.2 核心组件概览:Mapper、SQL 注入器、主键生成器等
MyBatis-Plus 作为一个功能丰富的持久层框架,拥有一些核心组件来支持其强大的功能。以下是 MyBatis-Plus 中一些关键的核心组件:
1. Mapper
Mapper 在 MyBatis-Plus 中扮演着至关重要的角色,它是数据库操作的入口。通过继承 BaseMapper
接口,开发者可以无需编写 XML 映射文件,直接通过 Java API 来执行数据库操作。Mapper 接口方法与 SQL 语句之间的映射是通过动态代理和运行时分析来实现的。
2. SQL 注入器 (SqlInjector)
SQL 注入器负责将 Mapper 接口中定义的方法注入为可执行的 SQL 语句。MyBatis-Plus 提供了默认的 SQL 注入器 DefaultSqlInjector
,它能够处理大多数基本的 SQL 映射需求。此外,开发者可以根据特定需求自定义 SQL 注入器,以支持复杂的 SQL 语句生成。
3. 主键生成器 (KeyGenerator)
MyBatis-Plus 的主键生成器用于自动生成数据库表的主键值。这在插入新记录时特别有用,特别是当数据库表使用自增主键或触发器生成主键时。通过实现 IKeyGenerator
接口,开发者可以自定义主键生成策略。
4. 乐观锁插件 (Pessimistic Lock Interceptor)
乐观锁插件是 MyBatis-Plus 提供的一个用于处理并发更新的功能组件。它通过在 SQL 更新语句中添加版本号或时间戳来实现乐观锁机制,从而避免在数据更新时发生冲突。
5. 字段自动填充功能 (MetaObjectHandler)
字段自动填充功能允许开发者自定义字段的自动填充策略,例如自动填充创建时间或更新时间。通过实现 MetaObjectHandler
接口,可以在插入或更新记录时自动填充这些字段。
6. 分页插件 (PaginationInterceptor)
分页插件是 MyBatis-Plus 中用于处理分页查询的组件。通过 PaginationInterceptor
,开发者可以轻松地对查询结果进行分页处理,而无需手动编写分页 SQL。
7. 条件构造器 (Wrapper)
条件构造器是 MyBatis-Plus 提供的一个强大工具,用于构建复杂的查询条件。通过链式调用,开发者可以方便地添加、组合各种查询条件,简化了复杂查询的构建过程。
8. 性能分析插件 (PerformanceInterceptor)
性能分析插件可以帮助开发者分析和诊断 SQL 语句的性能问题。通过 PerformanceInterceptor
,可以记录和输出执行的 SQL 语句及其执行时间,从而优化慢查询。
9. 插件管理器 (InterceptorChain)
插件管理器负责管理 MyBatis-Plus 中的各种插件,如分页插件、乐观锁插件等。通过 InterceptorChain
,可以灵活地添加、配置和管理这些插件。
1.3 MyBatis-Plus工作流程简介
MyBatis-Plus 作为 MyBatis 的增强框架,其工作流程在继承 MyBatis 的基础上进行了优化和扩展。以下是 MyBatis-Plus 的主要工作流程:
1. 配置和初始化
- 配置文件:开发者可以在配置文件中指定数据库连接信息、Mapper 扫描包等。
- 自动配置:通过 Spring Boot 的自动配置机制或 XML 配置,MyBatis-Plus 会初始化必要的组件,如 SqlSessionFactory、Mapper 扫描器等。
2. 定义 Mapper 接口
- 继承 BaseMapper:自定义的 Mapper 接口通常继承自 MyBatis-Plus 提供的 BaseMapper,以获得通用的 CRUD 支持。
- 注解和接口方法:通过注解或直接在接口中定义方法来声明需要执行的数据库操作。
3. 扫描和注册 Mapper
- Mapper 扫描器:MyBatis-Plus 会扫描定义的 Mapper 接口,并将它们注册到 Mybatis 的 Mapper 仓库中。
- 动态代理:MyBatis-Plus 使用动态代理模式为每个 Mapper 接口创建代理对象。
4. SQL 注入器的工作
- 方法映射:SQL 注入器负责将 Mapper 接口中的方法映射为相应的 SQL 语句。
- 自定义 SQL:对于注解中定义的 SQL,MyBatis-Plus 会将其注入到对应的 MappedStatement 中。
5. 执行数据库操作
- 代理对象调用:当调用 Mapper 代理对象的方法时,MyBatis-Plus 会拦截这些调用。
- SQL 执行:根据方法的签名和注解,MyBatis-Plus 构造 SQL 语句并执行数据库操作。
6. 结果处理
- 结果映射:执行结果会被 MyBatis-Plus 自动映射到相应的 Java 对象。
- 分页结果:如果操作是分页查询,MyBatis-Plus 还会处理分页逻辑,返回分页结果。
7. 事务管理
- 声明式事务:如果应用运行在 Spring 框架中,MyBatis-Plus 可以无缝集成 Spring 的声明式事务管理。
- 事务传播:支持 Spring 的事务传播行为,简化事务控制。
8. 性能监控与优化
- SQL 执行监控:MyBatis-Plus 允许开发者监控 SQL 的执行情况,包括执行时间和频率。
- 执行计划:提供执行计划分析,帮助开发者优化 SQL 语句。
9. 插件扩展
- 拦截器和插件:MyBatis-Plus 支持通过拦截器和插件来扩展或修改其行为,如分页插件、性能分析插件等。
工作流程图
第二章:Mapper 对象方法映射为 SQL 语句
在 MyBatis-Plus 中,Mapper 接口方法映射为 SQL 语句的过程是核心功能之一,它允许开发者通过简单的接口方法调用执行复杂的数据库操作。以下是该过程的详细步骤:
2.1 MybatisPlusAutoConfiguration 和 SqlSessionFactory 创建
- 自动配置类:
MybatisPlusAutoConfiguration
是 Spring Boot 的自动配置类,它负责初始化 MyBatis-Plus 的核心组件。 - 创建 SqlSessionFactory:通过
sqlSessionFactory()
方法配置SqlSessionFactory
,这是 MyBatis 中用于执行数据库操作的工厂类。
2.2 MybatisXMLConfigBuilder 和 XML 配置文件解析
- 配置构建器:
MybatisXMLConfigBuilder
负责解析 MyBatis 的配置文件和 Mapper XML 文件。 - 解析过程:读取 XML 文件中的配置信息,包括数据库连接信息、事务管理器、Mapper 映射等。
2.3 Mapper 接口方法与 SQL 语句的映射过程
- 接口方法定义:开发者在 Mapper 接口中定义方法,这些方法代表了要执行的数据库操作。
- 注解使用:通过注解(如
@Select
,@Update
,@Insert
,@Delete
)直接在接口方法上指定 SQL 语句或查询结果的处理方式。 - 动态 SQL:MyBatis-Plus 支持动态 SQL,允许根据条件动态拼接 SQL 语句。
2.4 SQL 语句的动态拼接和 MappedStatement 对象的创建
- 动态拼接:SQL 注入器(
SqlInjector
)根据 Mapper 接口中定义的方法和注解,动态拼接出完整的 SQL 语句。 - MappedStatement 对象:每个映射的 SQL 语句都被封装在一个
MappedStatement
对象中,该对象包含了执行 SQL 所需的所有信息,如 SQL 语句本身、参数信息、结果映射等。 - 注册到 MyBatis:创建的
MappedStatement
对象被注册到 MyBatis 的配置中,使得在运行时可以通过 Mapper 接口调用对应的 SQL 语句。
2.5 执行 SQL 语句
- 代理机制:MyBatis-Plus 使用动态代理机制,当调用 Mapper 接口的方法时,实际上是在调用代理对象的
invoke
方法。 - 执行查询或更新:根据
MappedStatement
中的信息,MyBatis-Plus 执行相应的 SQL 查询或更新操作。 - 结果处理:查询结果通过 MyBatis 的结果映射机制转换为 Java 对象,返回给开发者。
通过上述步骤,MyBatis-Plus 将 Mapper 接口方法映射为 SQL 语句,并提供了执行数据库操作的能力。这个过程不仅提高了开发效率,还保证了代码的简洁性和可维护性。
第三章:MyBatis-Plus 通用方法的自定义与实现
3.1 自定义通用方法的需求背景
在企业级应用开发中,经常会遇到一些特定的数据库操作需求,这些需求可能无法通过标准的 CRUD 操作来满足。例如,可能需要执行一些特殊的查询,或者在查询时应用特定的业务逻辑。为了应对这些需求,同时保持代码的整洁和可维护性,MyBatis-Plus 提供了自定义通用方法的能力。
3.2 新增 Mapper 方法与 SQL 语句脚本映射枚举
自定义通用方法的第一步是定义一个新的枚举,该枚举扩展了 MyBatis-Plus 的 SqlMethod
枚举。这个枚举将 Mapper 方法名映射到具体的 SQL 语句模板。例如,如果我们想要添加一个从主库查询数据的方法,我们可以定义一个 SqlMethodEx
枚举,如下所示:
public enum SqlMethodEx {
MASTER_SELECT_LIST("selectListFromMaster", "从主库查询满足条件的多条数据",
"<bind>" + SqlConstant.DA_MASTER_PARAM +
"SELECT ${ew.sqlSelect} FROM ${ew.sqlTable} ${ew.sqlWhere}" +
"</bind>");
private final String method;
private final String desc;
private final String sql;
SqlMethodEx(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}
public String getMethod() {
return method;
}
public String getDesc() {
return desc;
}
public String getSql() {
return sql;
}
}
3.3 新增通用方法的定义类和 SQL 注入器
接下来,需要创建一个通用方法的定义类,该类继承自 AbstractMethod
。在这个类中,我们将实现如何将自定义的 SQL 语句注入到 MyBatis-Plus 的框架中。例如,我们可以创建一个 SelectListFromMasterMethod
类:
public class SelectListFromMasterMethod extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethodEx sqlMethod = SqlMethodEx.MASTER_SELECT_LIST;
// ... 构建 SQL 语句 ...
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo);
}
private String getMethod(SqlMethodEx sqlMethod) {
return sqlMethod.getMethod();
}
}
此外,还需要扩展 SQL 注入器,以识别和处理这些自定义方法。这可以通过继承 DefaultSqlInjector
类并重写 getMethodList
方法来实现:
public class MasterSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methods = super.getMethodList(mapperClass);
methods.add(new SelectListFromMasterMethod());
return methods;
}
}
3.4 配置类和基类 Mapper 的扩展
最后,需要在 MyBatis-Plus 的配置类中注册自定义的 SQL 注入器,以确保框架在初始化时能够识别和使用这些注入器。这可以通过创建一个配置类并使用 @Bean
注解来完成:
@Configuration
public class MybatisPlusConfig {
@Bean
public MasterSqlInjector masterSqlInjector() {
return new MasterSqlInjector();
}
}
同时,我们可以在基类 Mapper 中添加自定义方法,这样任何继承该基类的 Mapper 接口都可以使用这些自定义方法。例如:
public interface MasterMapper<T> extends BaseMapper<T> {
@Select("<script>${ew.sqlSelect}</script>")
List<T> selectListFromMaster(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
通过这种方式,自定义通用方法就被成功添加到了 MyBatis-Plus 框架中,并且可以在应用程序中按需使用。这种方法大大提升了数据库操作的灵活性和代码的复用性。
第四章:MyBatis-Plus SQL 语句的处理与执行
MyBatis-Plus 中 SQL 语句的处理和执行是一个涉及多个步骤的复杂过程,从 SQL 语句的构建和解析到最终的执行。本章将详细分析这个过程。
4.1 SQL 语句脚本的构建和解析
SQL 语句脚本的构建是 MyBatis-Plus 动态 SQL 功能的核心。通过 SqlScriptUtils
工具类,开发者可以构建复杂的 SQL 语句,这些语句可以根据运行时的条件动态变化。
- 动态 SQL 模板:MyBatis-Plus 支持使用 XML 或注解中的 OGNL 表达式来构建动态 SQL。例如,可以使用
<if>
、<choose>
、<when>
、<otherwise>
等标签来构建条件语句。 - 工具类:
SqlScriptUtils
提供了多种方法来帮助开发者构建 SQL 语句,如convertIf
、convertChoose
等,这些方法可以处理复杂的逻辑并生成相应的 SQL 片段。
4.2 SqlSource 的转化和使用
一旦 SQL 语句脚本构建完成,下一步是将其转化为 SqlSource
对象。SqlSource
是 MyBatis 中用于执行 SQL 的核心对象,它包含了执行 SQL 所需的所有信息。
- LanguageDriver 接口:MyBatis-Plus 使用
LanguageDriver
接口来将 SQL 脚本转化为SqlSource
。默认实现是XMLLanguageDriver
,它负责解析 XML 中的 SQL 脚本。 - 创建 SqlSource:通过
LanguageDriver
的createSqlSource
方法,传入配置信息、SQL 脚本和参数类型,最终生成SqlSource
对象。
4.3 MappedStatement 的创建和缓存
MappedStatement
是 MyBatis 中用于存储与 Mapper 接口方法相关联的 SQL 信息的对象。
- 关联 SqlSource:将
SqlSource
对象与 Mapper 接口方法关联起来,封装在MappedStatement
中。 - 缓存:创建的
MappedStatement
被缓存到 MyBatis 的配置中,这样在 Mapper 接口方法被调用时,可以直接使用缓存中的MappedStatement
来执行 SQL。
4.4 执行 SQL 语句和参数处理
当 Mapper 接口方法被调用时,MyBatis-Plus 将执行与之关联的 SQL 语句。
- BoundSql 对象:MyBatis-Plus 使用
BoundSql
对象来处理参数的绑定和替换。它包含了 SQL 语句以及与之相关的参数信息。 - 参数映射:
BoundSql
中的参数映射(ParameterMapping
)定义了如何从 Mapper 接口方法的参数中提取值,并将其绑定到 SQL 语句的占位符上。 - 执行流程:MyBatis-Plus 通过
Executor
接口来执行 SQL。在执行前,会通过BoundSql
来替换 SQL 语句中的占位符,生成最终要执行的 SQL 语句。 - 结果处理:执行 SQL 后,MyBatis-Plus 会根据
MappedStatement
中定义的结果映射来处理查询结果,将数据库返回的数据映射到 Java 对象。
通过以上步骤,MyBatis-Plus 完成了从 SQL 语句的构建和解析到最终的执行和结果处理的整个流程。这个过程不仅提供了高度的灵活性和动态性,还保证了执行效率和结果的正确性。
第五章:MyBatis-Plus 源码深入分析
5.1 MyBatis-Plus 配置类和 Bean 的创建
在 MyBatis-Plus 的初始化过程中,配置类扮演着核心角色。MybatisPlusAutoConfiguration
是 Spring Boot 的自动配置类,它负责设置 MyBatis-Plus 的基础环境。
- 自动配置类:
MybatisPlusAutoConfiguration
根据应用程序的配置自动设置 MyBatis-Plus 的相关 Bean,如SqlSessionFactory
、MapperScannerConfigurer
等。 - Bean 的创建:自动配置类会创建
GlobalConfig
和MybatisPlusProperties
Bean,这些 Bean 包含了 MyBatis-Plus 的全局配置信息。
5.2 Mapper 接口的扫描和注册
MyBatis-Plus 通过 MapperScannerConfigurer
类来扫描指定包路径下的 Mapper 接口。
- Mapper 扫描:
MapperScannerConfigurer
使用ClassPathMapperScanner
来扫描指定的包路径,查找继承了Mapper
接口的类。 - 注册 Bean:扫描到的 Mapper 接口类会被注册为 Spring 的 Bean,这样 Spring 容器就可以管理这些 Mapper 接口的生命周期。
5.3 动态代理和数据库操作的执行流程
MyBatis-Plus 使用动态代理来实现对 Mapper 接口方法的拦截和执行。
- MapperFactoryBean:每个 Mapper 接口都会创建一个
MapperFactoryBean
,它负责创建 Mapper 接口的代理实例。 - 动态代理:当 Spring 容器需要一个 Mapper 接口的实例时,
MapperFactoryBean
会返回一个动态代理对象,该对象实现了 Mapper 接口。 - 执行流程:当调用 Mapper 接口的代理对象的方法时,会触发
MybatisMapperProxy
的invoke
方法,该方法负责构建 SQL 语句并执行数据库操作。
5.4 特殊情况处理:主从数据库路由、读写分离等
MyBatis-Plus 支持处理一些特殊情况,如读写分离和主从数据库路由。
- 读写分离:通过配置
GlobalConfig
中的DbConfig
,可以设置主从数据库的信息,以及如何进行读写分离。 - 主从路由:MyBatis-Plus 可以使用自定义的路由策略来决定每个查询应该路由到哪个数据库。这通常是通过实现
IRoute
接口来完成的。 - 执行策略:在执行 SQL 时,MyBatis-Plus 会根据配置的路由策略和当前的操作类型(读或写)来选择正确的数据库连接。
第六章 参考文献
-
谈说1974. (2023). MyBatis-plus 转化处理 SQL 语句的源码分析. CSDN 博客.
- 链接:MyBatis-plus 转化处理 SQL 语句的源码分析
- 摘要:本文详细介绍了 MyBatis-plus 是如何处理和转换 SQL 语句脚本的,包括 SQL 语句脚本的构建和 SqlSource 的转化等关键步骤。
-
Nathan. (2023). MyBatis-plus 自定义通用方法及其实现原理. CSDN 博客.
- 链接:MyBatis-plus 自定义通用方法及其实现原理
- 摘要:文章讨论了在 MyBatis-plus 中如何自定义通用方法,包括新增 Mapper 方法与 SQL 语句脚本映射枚举、通用方法的定义类、SQL 注入器,以及如何在配置类中注册自定义 SQL 注入器。
-
谈说1974. (2020). MyBatis-plus 源码解析. CSDN 博客.
- 链接:MyBatis-plus 源码解析
- 摘要:这篇源码解析文章深入探讨了 MyBatis-plus 的工作原理,包括 Mapper 对象方法如何映射为 SQL 语句、MyBatis-Plus 的自动配置类如何配置 SqlSessionFactory,以及 Mapper 操作数据库的流程。
-
MyBatis-Plus 官方文档
-
摘要:官方文档提供了 MyBatis-Plus 的全面指南,包括快速入门、核心功能介绍、配置参考以及最佳实践等。
-
MyBatis-Plus GitHub 仓库
-
摘要:GitHub 仓库是 MyBatis-Plus 的源代码存放地,提供了框架的最新代码、issue 跟踪以及 pull request 功能,是贡献者和用户交流的重要平台。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)