一条 SQL 在 MyBatis 里到底经历了什么?
上一篇我们讲了:
MyBatis 为什么知道该执行哪条 SQL?
核心答案是:
Mapper方法
↓
MappedStatement
MyBatis 在启动时已经建立好了映射关系。
但是新的问题来了。
找到 SQL 只是第一步。真正执行 SQL 的过程又是怎样的?
例如:
User user = userMapper.selectById(1L);
看起来只有一行代码。
但实际上。
从 Mapper 到数据库,中间经过了很多组件。
今天我们就把这条链路彻底看明白。
从 Mapper 开始
执行:
userMapper.selectById(1L);
首先进入:
MapperProxy
上一篇已经讲过。
Mapper 本质上是动态代理对象。
最终会进入:
MapperProxy.invoke()
这里会找到对应的:
MapperMethod
然后执行:
mapperMethod.execute(sqlSession, args);
接下来正式进入 MyBatis 核心执行流程。
SqlSession 登场
很多人学 MyBatis 时。
最容易忽略的其实是:
SqlSession
但实际上。
它才是真正的执行入口。
例如:
sqlSession.selectOne(...)
sqlSession.insert(...)
sqlSession.update(...)
Mapper 最终也是调用它。
所以:
Mapper
↓
SqlSession
这是第一层关系。
真正执行 SQL 的是谁?
很多人以为:
SqlSession
直接操作数据库,其实不是。
继续往下会进入:
Executor
源码:
executor.query(...)
这里出现了 MyBatis 最重要的组件之一:
Executor
你可以把它理解成:
SQL 执行总管
Executor 到底负责什么?
它主要负责:
缓存处理、SQL执行、事务管理、结果返回
无论:
select
insert
update
delete
最终都会走到:
Executor
所以:
SqlSession
↓
Executor
是 MyBatis 执行链路最核心的一层。
Executor 会直接操作 JDBC 吗?
还是不会,继续往下,会进入:
StatementHandler
很多人第一次看到这个类名。
会觉得很普通,实际上非常关键。
因为 JDBC 的核心对象就是:
Statement
PreparedStatement
而:
StatementHandler
就是专门处理这些对象的。
SQL 是什么时候变成 PreparedStatement 的?
假设 Mapper 中写:
<select id="selectById">
select * from user where id = #{id}
</select>
此时 SQL 还是:
select * from user where id = #{id}
进入:
StatementHandler
以后。
MyBatis 会处理成:
select * from user where id = ?
然后创建:
PreparedStatement
准备执行。
参数是谁设置进去的?
新的问题又来了。
既然变成:
select * from user where id = ?
那:
1L
怎么放进去?这里会进入:
ParameterHandler
负责参数绑定。
例如:
ps.setLong(1,1L);
最终变成:
select * from user where id = 1
准备发送数据库
数据库返回结果以后呢?
执行完成后。
数据库返回:
ResultSet
例如:
id=1
name=Tom
age=18
但是业务代码需要的是:
User
对象。
于是进入:
ResultSetHandler
负责结果映射。
把:
ResultSet
转换成:
User
对象。
最终返回给业务代码。
整个执行链路
现在把所有组件串起来。
执行:
userMapper.selectById(1L);
实际流程:
MapperProxy
↓
MapperMethod
↓
SqlSession
↓
Executor
↓
StatementHandler
↓
ParameterHandler
↓
JDBC
↓
Database
↓
ResultSet
↓
ResultSetHandler
↓
User对象
这才是一条 SQL 完整的生命周期。
为什么要拆这么多组件?
很多人第一次看源码会觉得:
太复杂了
直接一个类执行完不行吗?
当然可以,但扩展性会很差。
MyBatis 的设计思想是:
一个组件只负责一件事
例如:
Executor负责执行
StatementHandler负责SQL
ParameterHandler负责参数
ResultSetHandler负责结果
以后要扩展,只需要替换对应组件即可。
这也是后面插件机制能够实现的基础。
真正的核心是谁?
如果只保留一个组件。
那一定是:
Executor
因为:
SqlSession是门面
StatementHandler是工具
ParameterHandler是辅助
ResultSetHandler是辅助
而:
Executor
才是真正控制整个 SQL 执行过程的人。
后面缓存机制、插件机制、事务机制。
本质上也都是围绕 Executor 展开的。
总结
执行:
userMapper.selectById(1L);
看起来只是一个普通方法调用。
实际上经历了完整执行链路:
MapperProxy
↓
SqlSession
↓
Executor
↓
StatementHandler
↓
ParameterHandler
↓
数据库
↓
ResultSetHandler
↓
Java对象
所以:
一条 SQL 在 MyBatis 里并不是直接执行的,而是经过多个组件协同完成。
而整个链路的核心。
就是:
Executor
理解了它,就理解了 MyBatis 执行流程的核心。
上一篇:
《MyBatis 为什么知道该执行哪条 SQL?》
下一篇:
《查询结果为什么能自动变成 Java 对象?》

