mybatis-plus原理
Mybatis-Plus (MP) 的核心原理可以理解为在 MyBatis 基础之上,通过一系列巧妙的封装、扩展和自动化机制,极大地简化了单表 CRUD 操作和常见功能的开发。其核心原理主要包括以下几个方面:
自动配置与集成 (Spring Boot Starter):
- MP 提供了
mybatis-plus-boot-starter
,利用 Spring Boot 的自动配置机制。 - 启动时,自动配置类 (
MybatisPlusAutoConfiguration
) 会:- 根据配置 (
application.yml/properties
) 创建并配置DataSource
。 - 创建并配置
SqlSessionFactoryBean
,并自动注入 MP 的核心组件(如GlobalConfig
,Interceptor
等)。 - 配置
MapperScannerConfigurer
,自动扫描并注册 Mapper 接口。
- 根据配置 (
- MP 提供了
核心接口
BaseMapper
:- 这是 MP 的核心创新点之一。用户自定义的 Mapper 接口只需要继承
BaseMapper
并指定泛型为对应的实体类。 BaseMapper
中预定义了大量的通用 CRUD 方法,如insert
,deleteById
,updateById
,selectById
,selectList
,selectPage
等。- 原理: MP 在运行时,会通过 MyBatis 的动态代理机制,为继承了
BaseMapper
的接口生成代理对象。当调用这些预定义方法时,代理对象会根据方法名、参数类型、实体类信息等,动态生成对应的 SQL 语句并执行。用户无需为这些通用操作编写任何 SQL 或 XML。
- 这是 MP 的核心创新点之一。用户自定义的 Mapper 接口只需要继承
SQL 自动生成机制 (
AbstractMethod
/SqlInjector
):- 这是
BaseMapper
功能实现的核心引擎。 - MP 内部定义了一个枚举类
SqlMethod
,包含了各种 CRUD 操作对应的 SQL 语句模板(如INSERT_ONE
,DELETE_BY_ID
,SELECT_BY_ID
)。 - 对于
BaseMapper
中的每个方法,MP 都有一个对应的AbstractMethod
子类(如Insert
,DeleteById
,SelectById
)。这些类负责:- 解析方法签名和参数。
- 获取实体类的元数据信息(通过
TableInfo
类,该类在应用启动时根据实体类注解如@TableName
,@TableId
,@TableField
等构建)。 - 将
SqlMethod
中的 SQL 模板与实体元数据结合,动态组装出最终要执行的、包含真实表名和字段名的完整 SQL 语句。 - 将组装好的 SQL 和参数传递给 MyBatis 执行。
SqlInjector
(如DefaultSqlInjector
) 负责将AbstractMethod
的实现“注入”到 Mapper 接口的代理对象中,使其拥有执行这些方法的能力。
- 这是
条件构造器 (
Wrapper
):- 提供了
QueryWrapper
,UpdateWrapper
,LambdaQueryWrapper
,LambdaUpdateWrapper
等强大的条件构造工具。 - 原理: 用户通过链式调用(如
.eq("name", "Alice")
,.gt("age", 18)
,.like("email", "@gmail.com")
)构建复杂的查询或更新条件。 Wrapper
内部将这些条件表达式解析并存储为一个抽象语法树(AST)或类似结构。- 当
Wrapper
被用于查询(如selectList(wrapper)
)或更新(如update(entity, wrapper)
)时,MP 的 SQL 生成引擎会:- 解析
Wrapper
中的条件表达式。 - 将这些条件安全地(防止 SQL 注入)拼接到自动生成的基础 SQL(如
SELECT * FROM table_name WHERE ...
或UPDATE table_name SET ... WHERE ...
)的WHERE
子句中。 - 将条件中使用的参数值正确地设置到
PreparedStatement
中。
- 解析
- 提供了
分页插件 (
PaginationInnerInterceptor
):- MP 通过实现 MyBatis 的
Interceptor
接口,提供了一个强大的分页插件。 - 原理:
- 当执行一个需要分页的查询方法(如
selectPage(Page page, @Param("ew") Wrapper queryWrapper)
)时,插件会拦截Executor
的query
方法。 - 插件首先会自动生成并执行一个
COUNT
查询,获取满足条件的数据总数。 - 然后,插件会重写原始查询的 SQL,根据传入的
Page
对象(包含current
,size
)添加数据库方言特定的分页语句(如 MySQL 的LIMIT offset, size
, Oracle 的 ROWNUM 等)。 - 执行修改后的分页 SQL,获取当前页数据。
- 最后,将总数和当前页数据封装到
Page
对象中返回。
- 当执行一个需要分页的查询方法(如
- MP 通过实现 MyBatis 的
全局配置与元数据处理器:
GlobalConfig
: 存储全局配置信息,如表名前缀/后缀、主键生成策略(IdentifierGenerator
)、元数据处理器(MetaObjectHandler
)等。MetaObjectHandler
:用于实现自动填充功能(如@TableField(fill = FieldFill.INSERT/UPDATE)
)。在执行插入或更新操作时,MP 会通过反射调用MetaObjectHandler
的insertFill
或updateFill
方法,自动填充字段值(如创建时间、更新时间、操作人)。
实体类注解驱动:
- MP 通过注解(
@TableName
,@TableId
,@TableField
,@Version
,@EnumValue
,@TableLogic
等)来获取 ORM 映射信息、主键策略、逻辑删除标志、枚举处理、乐观锁标识等。 - 这些注解信息在应用启动时被解析并存储在
TableInfo
等元数据对象中,供 SQL 生成引擎、条件构造器、插件等组件使用。
- MP 通过注解(
总结 Mybatis-Plus 的核心原理:
- 基于 MyBatis 扩展: 完全兼容 MyBatis,利用其插件、动态代理、映射器机制。
- 动态 SQL 生成: 核心在于通过
BaseMapper
接口和SqlInjector
机制,根据方法签名和实体元数据动态生成常用 CRUD 的 SQL。 - 强大条件封装: 通过
Wrapper
以面向对象的方式安全、便捷地构建复杂查询/更新条件。 - 插件增强: 利用 MyBatis 拦截器实现分页、性能分析、乐观锁等高级功能。
- 注解驱动配置: 通过注解简化 ORM 配置和特殊功能(逻辑删除、自动填充、乐观锁)的使用。
- 自动化: 目标是最大程度减少开发者编写样板代码(尤其是单表操作),提高开发效率。
简而言之,Mybatis-Plus 通过动态代理、元数据解析、SQL 模板拼接、拦截器扩展等技术,在 MyBatis 的基础上实现了通用 CRUD 操作的零 SQL 编码和复杂查询的便捷构建,同时保持了 MyBatis 的灵活性和强大功能。