

解释:

这是xml格式的MyBatis的配置文件

追踪MyBatis的执行过程中的参数


MyBatis 是一个优秀的持久层框架,它通过 XML 或注解的方式将 SQL 语句与 Java 对象进行映射,简化了 JDBC 的操作。理解 MyBatis 的执行流程,有助于掌握其底层原理,提升开发效率和排查问题能力。
🌟 一、MyBatis 执行流程概览(以 select 为例)
1. 加载配置并初始化 SqlSessionFactory
2. 创建 SqlSession
3. 获取 Mapper 接口代理对象
4. 调用 Mapper 方法
5. 执行 SQL:解析 SQL、参数处理、执行、结果映射
6. 返回结果
7. 提交或关闭 SqlSession
🔍 二、详细执行流程(图解 + 说明)
✅ 阶段1:初始化 —— 创建 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
流程:
- 读取
mybatis-config.xml主配置文件(数据源、事务、Mapper 映射文件位置等) - 读取
<mappers>中的 SQL 映射文件(如UserMapper.xml) - 解析 SQL 映射文件,构建
MappedStatement对象(封装 SQL、参数类型、返回类型等) - 创建
SqlSessionFactory(工厂模式,用于创建SqlSession)
📌
SqlSessionFactory是线程安全的,通常整个应用只有一个实例。
✅ 阶段2:获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession是 MyBatis 的核心接口,代表一次数据库会话。- 封装了所有执行 SQL 的方法:
selectOne(),selectList(),insert(),update(),delete()等。 - 不是线程安全,每次请求应创建或从线程池获取。
✅ 阶段3:获取 Mapper 代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
MyBatis 做了什么?
- 使用 JDK 动态代理,为
UserMapper接口生成代理对象。 - 代理逻辑:拦截接口方法调用,根据方法名找到对应的 SQL 语句(
namespace + id)。
📌 例如:
UserMapper.selectById(id)→com.example.mapper.UserMapper.selectById
✅ 阶段4:执行 SQL(核心流程)
当你调用:
User user = mapper.selectById(1L);
MyBatis 内部执行流程如下:
🔁 4.1 根据方法名查找 MappedStatement
- 通过接口全限定名 + 方法名,找到对应的
MappedStatement(在初始化时已加载)
<!-- UserMapper.xml -->
<select id="selectById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
→ 找到 MappedStatement,包含:
- SQL 语句
- 参数类型
- 返回类型
- 执行器类型等
🔁 4.2 参数处理(ParameterHandler)
- 将方法参数(如
1L)封装成BoundSql - 处理
#{}和${}:#{id}→ 预编译占位符?,防止 SQL 注入${id}→ 字符串拼接,需谨慎使用
- 生成最终 SQL:
SELECT * FROM user WHERE id = ?
🔁 4.3 执行 SQL(Executor + StatementHandler)
- Executor(执行器):负责 SQL 执行和一级缓存
SimpleExecutor:默认,每次重新 prepareReuseExecutor:重用 StatementBatchExecutor:批量执行
- StatementHandler:使用 JDBC 的
PreparedStatement执行 SQL- 设置参数
- 执行
executeQuery()或executeUpdate()
🔁 4.4 结果映射(ResultSetHandler)
- 获取
ResultSet - 根据
resultType或resultMap进行映射:- 简单类型:直接返回(如
int,String) - POJO 类型:通过反射创建对象,设置字段值
- 复杂映射:处理一对一、一对多(嵌套查询或嵌套结果)
- 简单类型:直接返回(如
// 自动映射:列名 → 属性名(支持驼峰转下划线)
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
// ...
✅ 阶段5:返回结果
- 将映射后的结果返回给调用方
selectOne()→ 单个对象selectList()→ Listinsert()→ 影响行数
✅ 阶段6:事务提交与关闭
// 如果是手动提交模式,需要显式提交
sqlSession.commit();
// 关闭资源
sqlSession.close();
🧩 三、核心组件关系图
SqlSessionFactoryBuilder
↓
SqlSessionFactory ——(唯一)——→ Configuration
↓
SqlSession ——(每次请求)——→ Executor ——→ StatementHandler
↓ ↓ ↓
Mapper Proxy ParameterHandler ResultSetHandler
↓
调用方法 → 触发执行
🔁 四、一级缓存 & 二级缓存
1. 一级缓存(Local Cache)
- 默认开启,基于
SqlSession - 同一个
SqlSession中,相同 SQL 和参数会从缓存中取结果 - 在
commit()或close()时清空
2. 二级缓存(Global Cache)
- 基于
namespace(Mapper 接口) - 需要手动开启:
<cache/>或@CacheNamespace - 跨
SqlSession共享,需序列化支持
✅ 五、使用注解时的流程
MyBatis 也支持注解方式:
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
流程基本一致,只是:
- SQL 从 XML 改为注解解析
- 初始化时通过反射读取注解,构建
MappedStatement
✅ 六、与 Spring 集成时的变化
在 Spring 中使用 MyBatis(如 mybatis-spring):
SqlSessionFactory由 Spring 容器管理- Mapper 接口通过
@MapperScan自动注册为 Bean - 不用手动获取
SqlSession,直接@Autowired注入 Mapper - 事务由 Spring 的
@Transactional管理
✅ 七、总结:MyBatis 执行流程口诀
🎯 “一工二会三代理,四找五参六执行,七映八果九关闭。”
| 步骤 | 说明 |
|---|---|
| 一工 | 创建 SqlSessionFactory |
| 二会 | 获取 SqlSession |
| 三代理 | 获取 Mapper 代理对象 |
| 四找 | 根据方法名找 MappedStatement |
| 五参 | 参数处理 → BoundSql |
| 六执行 | Executor 执行 SQL |
| 七映 | ResultSetHandler 结果映射 |
| 八果 | 返回结果 |
| 九关闭 | 提交事务,关闭 SqlSession |
💡 最佳实践建议
- 优先使用
#{}防止 SQL 注入 - 复杂映射使用
resultMap,简单用resultType - 合理使用一级/二级缓存提升性能
- Mapper 接口与 XML 文件保持命名一致
- 在 Spring 中使用
@Mapper或@MapperScan
掌握 MyBatis 的执行流程,你就能真正理解它“半自动化”ORM 的魅力!
235

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



