执行流程
问题
MyBatis 的整体架构是怎样的?一条 SQL 从发起到返回结果经历了哪些步骤?
答案
MyBatis 架构分层
SQL 执行完整流程
核心组件详解
| 组件 | 职责 |
|---|---|
| SqlSessionFactory | 创建 SqlSession 的工厂,全局唯一 |
| SqlSession | 和数据库交互的会话,非线程安全 |
| Executor | SQL 执行器,有 Simple/Reuse/Batch 三种 |
| MappedStatement | 封装一条 SQL 的完整信息(SQL、参数映射、结果映射) |
| StatementHandler | 创建和操作 JDBC Statement |
| ParameterHandler | 将 Java 参数设置到 PreparedStatement |
| ResultSetHandler | 将 JDBC ResultSet 映射为 Java 对象 |
| TypeHandler | Java 类型 ↔ JDBC 类型的双向转换 |
三种 Executor
| Executor | 特点 |
|---|---|
| SimpleExecutor | 每次执行创建新的 Statement(默认) |
| ReuseExecutor | 相同 SQL 复用 Statement |
| BatchExecutor | 批量执行 update(addBatch/executeBatch) |
Executor 选择
// 默认 SimpleExecutor
SqlSession session = sqlSessionFactory.openSession();
// 指定 Executor 类型
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
SqlSession 工作原理
SqlSession 使用(原始方式)
try (SqlSession session = sqlSessionFactory.openSession()) {
// 方式1:直接使用 SqlSession
User user = session.selectOne("com.example.mapper.UserMapper.getById", 1L);
// 方式2:通过 Mapper 接口(推荐)
UserMapper mapper = session.getMapper(UserMapper.class);
User user2 = mapper.getById(1L);
session.commit();
}
SqlSession 线程安全
SqlSession 是非线程安全的,不能作为成员变量共享。在 Spring 中,SqlSessionTemplate 通过动态代理为每次调用创建新的 SqlSession,保证线程安全。
常见面试问题
Q1: MyBatis 的执行流程?
答案:
- 应用通过 Mapper 接口调用方法
- Mapper 代理将方法调用转化为
SqlSession.selectOne/insert/update/delete - SqlSession 委托给 Executor 执行
- Executor 先查缓存(一级 → 二级),命中则直接返回
- 未命中则创建 StatementHandler
- ParameterHandler 通过 TypeHandler 设置 SQL 参数
- 执行 JDBC 操作
- ResultSetHandler 通过 TypeHandler 将结果映射为 Java 对象
- 结果放入一级缓存后返回
Q2: #{} 和 ${} 的区别?
答案:
#{}:预编译参数,使用PreparedStatement的?占位符,防止 SQL 注入${}:字符串拼接,直接将值拼入 SQL,有 SQL 注入风险
#{} 用于传值(where 条件、insert 值),${} 仅用于动态表名、列名等无法预编译的场景。
Q3: Mapper 接口没有实现类,是怎么工作的?
答案:
MyBatis 通过 JDK 动态代理 实现。SqlSession.getMapper(UserMapper.class) 返回的是一个代理对象,调用接口方法时,代理拦截调用,根据方法的全限定名(类名.方法名)找到对应的 MappedStatement,最终委托给 SqlSession 执行 SQL。
Q4: MyBatis 中 XML 和注解方式的区别?
答案:
| 方式 | 优点 | 缺点 |
|---|---|---|
| XML | 适合复杂 SQL,便于维护 | 文件多,需要额外配置 |
| 注解 | 简单直接,无需额外文件 | 复杂 SQL 不方便 |
实际项目中常混用:简单 CRUD 用注解,复杂查询用 XML。
相关链接
- MyBatis 官方文档
- Spring 中的设计模式 - 代理模式