MyBatis 与 MyBatis-Plus 底层机制原理深度剖析
本文基于 MyBatis 3.5.x 及 MyBatis-Plus 3.5.5 最新源码与官方文档,结合生产实践,对两条技术栈的启动流程、SQL 执行链路、插件体系、功能增强点做一次性梳理,帮助你在架构选型、性能调优、二次开发时做到“选型有据、调优有数、扩展有方”。
一、MyBatis 底层核心机制
1.1 启动链路:从配置文件到 SqlSession
阶段关键类职责解析配置SqlSessionFactoryBuilder读取 mybatis-config.xml 与 Mapper.xml,构建 Configuration 单例创建工厂SqlSessionFactory基于 Configuration 生成,线程安全会话实例SqlSession每次请求新建,持有 Executor 与一级缓存代理生成MapperProxyFactory使用 JDK 动态代理创建 Mapper 接口实现// 伪代码:启动入口
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
1.2 SQL 执行链路
调用 mapper.selectById(1L)
→ MapperProxy.invoke() // 拦截接口调用
→ MapperMethod.execute() // 根据 SQL 类型分发
→ DefaultSqlSession.selectOne() // 打开会话
→ CachingExecutor.query() // 二级缓存
→ SimpleExecutor.doQuery() // 真正 JDBC 执行
→ StatementHandler.prepare() // 创建 Statement
→ ParameterHandler.setParameters() // 绑定参数
→ ResultSetHandler.handleResultSets() // 结果映射
动态 SQL:通过 OGNL + SqlNode 树在运行时拼接 SQL。延迟加载:基于 CGLIB 代理,在第一次访问属性时才触发子查询。缓存:
一级缓存默认开启,生命周期同 SqlSession;二级缓存 mapper 级别,依赖
二、MyBatis-Plus 的“增强”到底做了哪些事?
MyBatis-Plus 只做“无侵入增强”:在 MyBatis 原有执行链路上,通过 MybatisPlusInterceptor → InnerInterceptor 责任链 追加功能。
2.1 启动差异
维度MyBatisMyBatis-Plus工厂构建手动 SqlSessionFactoryBuilderMybatisPlusAutoConfiguration(Spring Boot Starter)配置注入XML/JavaConfigapplication.yml + MybatisPlusPropertiesMapper 注册
MyBatis-Plus 执行链路
├─ 分页:PaginationInnerInterceptor
├─ 乐观锁:OptimisticLockerInnerInterceptor
├─ 多租户:TenantLineInnerInterceptor
└─ 数据权限:DataPermissionInterceptor
BaseMapper 原理:在启动时,MyBatis-Plus 会把通用 CRUD 的 XML 模板注入到 Configuration 中,从而无需手写 SQL。条件构造器:QueryWrapper 内部维护 SQLSegments,最终拼成 BoundSql,与手写 SQL 无性能差异。
三、插件机制对比
能力MyBatis InterceptorMyBatis-Plus InnerInterceptor拦截点Executor/ParameterHandler/ResultSetHandler/StatementHandler细化到 willDoQuery / beforeUpdate 等 7 个阶段注册方式
public class TimeSyncInnerInterceptor implements InnerInterceptor {
@Override
public boolean willDoUpdate(Executor executor, MappedStatement ms, Object parameter) {
if (parameter instanceof User) {
User u = (User) parameter;
u.setCreateTime(u.getOrderTime());
}
return true;
}
}
四、性能与可维护性对比
维度MyBatisMyBatis-Plus建议开发效率手写 SQL & XML通用 Mapper + 条件构造器80% 场景优先 Plus灵活性极高中(复杂 SQL 需自定义 SQL)复杂报表仍用 MyBatis批量操作手写 foreachsaveBatch + rewriteBatchedStatementsPlus 性能更优缓存需手动配置 Redis 二级与 MyBatis 保持一致共用策略升级成本低注意版本差异(3.5.x 起 JDK17+)锁定 LTS 版本
五、选型与落地建议
新项目:直接采用 MyBatis-Plus + Spring Boot 3 Starter,90% CRUD 零 SQL。老项目:可渐进式替换:先引入 Plus,保留原有 Mapper,逐步迁移到 BaseMapper。复杂场景:
报表、存储过程 → 继续用 MyBatis XML;多租户、数据权限 → 使用 Plus 插件链 + 自定义 InnerInterceptor。
团队技能:初级团队 Plus 降低门槛;资深团队利用 Plus 插件 SPI 做框架级扩展。
六、小结
MyBatis 是“SQL 引擎”,掌握 XML + 拦截器即可玩出花;MyBatis-Plus 是“生产力工具”,在 MyBatis 之上用 约定大于配置 的思想,把 CRUD、分页、乐观锁等高频需求做成 可插拔组件。
两者并非“取代”,而是 组合使用:MyBatis 负责深度定制,Plus 负责提效。理解底层后,你可以自由地在二者之间“按需切换、无缝增强”。
没有套路,真实资料!