下面是对 MyBatis 源码的深入剖析,重点围绕其 本质与核心特性 展开详细解析。通过理解 MyBatis 的设计思想、架构组成和运行机制,你将掌握它为何能在持久层框架中占据重要地位。
🔍 一、MyBatis 的本质
✅ 一句话定义:
MyBatis 是一个“半自动化”的持久层框架,本质是 JDBC 的增强工具,它封装了 JDBC 的重复代码,同时保留 SQL 的完全控制权。
🧠 与“全自动”ORM框架(如 Hibernate)对比:
| 特性 | MyBatis | Hibernate |
|---|---|---|
| SQL 控制 | 手写 SQL,完全可控 | 自动生成 SQL,灵活性差 |
| 学习成本 | 低,贴近 JDBC | 高,需掌握 HQL 和映射规则 |
| 性能优化 | 易于调优(可写复杂 SQL) | 受限于生成的 SQL |
| 自动化程度 | 半自动(手动写 SQL + 自动映射结果) | 全自动(对象 ↔ 表 自动映射) |
💡 所以:MyBatis 的本质是“SQL 映射框架”,而不是传统意义上的 ORM 框架。
🏗️ 二、MyBatis 的核心特性
1. SQL 与代码分离(解耦)
- SQL 写在 XML 文件或注解中,与 Java 代码解耦。
- 支持动态 SQL(
<if>,<choose>,<foreach>等),灵活构建查询。
<select id="findUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
</select>
2. 自动映射(Result Mapping)
- 将查询结果自动映射为 Java 对象(POJO)。
- 支持
resultType(简单类型)和resultMap(复杂关系,如一对多、嵌套对象)。
<resultMap id="userMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<association property="role" javaType="Role" resultMap="roleMap"/>
</resultMap>
3. 动态 SQL
- 使用 OGNL 表达式 + XML 标签动态拼接 SQL。
- 避免手动拼接字符串,防止 SQL 注入,提升可维护性。
4. 插件机制(Interceptor)
- 提供
Executor,StatementHandler,ParameterHandler,ResultSetHandler四大接口的拦截能力。 - 可实现分页、日志、性能监控、数据加密等通用功能。
@Intercepts({@Signature(type = Executor.class, method = "query", args = { ... })})
public class MyPlugin implements Interceptor {
public Object intercept(Invocation invocation) {
// 拦截执行逻辑
}
}
5. 缓存机制(一级 & 二级缓存)
- 一级缓存:基于
SqlSession的会话级缓存,默认开启。 - 二级缓存:基于
namespace(Mapper 接口)的跨会话缓存,需手动开启。
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
⚠️ 注意:二级缓存可能导致脏读,高并发下建议使用 Redis 替代。
6. 灵活的配置方式
- 支持 XML 配置 和 注解 两种方式。
- 可与 Spring 集成,通过
@MapperScan自动注册 Mapper 接口。
🧩 三、MyBatis 核心组件架构图(源码视角)
+---------------------+
| SqlSessionFactory | ← 通过 SqlSessionFactoryBuilder 构建
+----------+----------+
|
| openSession()
v
+---------------------+
| SqlSession | ← 线程不安全,每次请求应创建新实例
+----------+----------+
|
| getMapper(UserMapper.class)
v
+---------------------+
| Mapper Proxy | ← JDK 动态代理生成接口实现
+----------+----------+
|
| execute()
v
+---------------------+
| Executor (执行器) | ← SimpleExecutor, ReuseExecutor, BatchExecutor
|
| 拦截(可被插件增强)
v
+---------------------+
| StatementHandler | ← 处理 PreparedStatement / CallableStatement
+----------+----------+
|
v
+---------------------+
| ParameterHandler | ← 设置 SQL 参数
+----------+----------+
|
v
+---------------------+
| ResultSetHandler | ← 处理结果集映射
+---------------------+
🔧 四、MyBatis 源码核心流程剖析
1. 初始化阶段(构建 SqlSessionFactory)
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- 解析
mybatis-config.xml:使用XPathParser解析全局配置。 - 解析
Mapper.xml:注册MappedStatement(封装 SQL、参数、返回类型等)。 - 生成
Configuration对象:保存所有配置信息,是 MyBatis 的“大脑”。
📌 源码入口:
XMLConfigBuilder.parse()
2. 获取 SqlSession(执行会话)
SqlSession session = sqlSessionFactory.openSession();
- 创建
Executor(根据isCommit、isReadOnly等选择类型)。 - 封装
Transaction(事务管理器)。 - 返回
DefaultSqlSession实例。
3. 获取 Mapper 接口代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
- 使用
MapperProxyFactory创建 JDK 动态代理。 - 代理逻辑由
MapperProxy实现,拦截所有方法调用。
📌 关键类:
MapperProxy,MapperMethod
4. 执行 SQL(方法调用触发)
User user = mapper.findUserById(1);
执行流程:
MapperProxy.invoke()→ 找到对应的MapperMethodMapperMethod.execute()→ 根据 SQL 类型(SELECT/INSERT/UPDATE/DELETE)调用sqlSession.selectOne()SimpleExecutor.query()→ 经过缓存检查StatementHandler.prepare()→ 创建PreparedStatementParameterHandler.setParameters()→ 设置参数StatementHandler.query()→ 执行 SQLResultSetHandler.handleResultSets()→ 映射结果集 → 返回User
🌟 五、MyBatis 的设计亮点(源码级理解)
| 设计模式 | 应用场景 | 说明 |
|---|---|---|
| 建造者模式 | SqlSessionFactoryBuilder | 构建复杂的 SqlSessionFactory |
| 工厂模式 | ObjectFactory, DataSourceFactory | 创建对象和数据源 |
| 代理模式 | MapperProxy | 动态生成 Mapper 接口实现 |
| 模板方法模式 | BaseExecutor | 定义执行流程,子类实现差异逻辑 |
| 责任链模式 | Interceptor 插件链 | 多个插件依次拦截处理 |
| 适配器模式 | TypeHandler | 将 Java 类型与 JDBC 类型适配 |
📈 六、MyBatis 的适用场景
✅ 推荐使用场景:
- 需要精细控制 SQL(如复杂查询、分页、多表联查)
- 已有数据库,需反向工程(数据库优先开发)
- 性能敏感系统(可优化每一条 SQL)
- 团队熟悉 SQL,追求灵活性
❌ 不推荐场景:
- 快速原型开发(不如 JPA 快)
- 数据库频繁变更(XML 维护成本高)
- 完全不想写 SQL
🧰 七、MyBatis Plus 与原生 MyBatis 对比
| 特性 | MyBatis | MyBatis Plus |
|---|---|---|
| CRUD 操作 | 需写 SQL | 提供 IService 自动生成 |
| 分页 | 手动写分页 SQL 或插件 | 内置分页插件 |
| 条件构造 | 原生 SQL | 提供 QueryWrapper |
| 代码生成 | 无 | 提供代码生成器 |
| 本质 | SQL 映射框架 | MyBatis 增强工具 |
💡 MyBatis Plus 是 MyBatis 的“增强版”,但核心仍是 MyBatis。
✅ 总结:MyBatis 的本质与价值
| 维度 | 说明 |
|---|---|
| 本质 | JDBC 的轻量级封装,SQL 映射框架 |
| 核心价值 | 让开发者专注于 SQL,同时享受 ORM 的便利 |
| 设计理念 | “不要试图隐藏 SQL,而是更好地管理它” |
| 源码启示 | 简洁、解耦、扩展性强,是学习 Java 框架设计的优秀范本 |
📚 延伸学习建议
-
阅读源码起点:
SqlSessionFactoryBuilder.build()XMLMapperBuilder.parse()MapperProxy.invoke()SimpleExecutor.query()
-
调试建议:
- 使用 Debug 跟踪
mapper.selectList()的完整调用链。 - 自定义
Interceptor观察四大对象的拦截时机。
- 使用 Debug 跟踪
-
推荐书籍:
- 《MyBatis 技术内幕》—— 深入源码分析
- 《Java 持久层框架:MyBatis 设计与实现》
1634

被折叠的 条评论
为什么被折叠?



