MyBatis 核心架构:面试官想听的「不只是组件罗列」——深入本质的讲解
💡面试真实场景提醒:如果你只答出“SqlSessionFactory、SqlSession、Executor……这些组件”,面试官大概率会皱眉,然后追问:“那它们之间怎么协作?谁控制流程?谁负责缓存?谁做SQL预编译?如果我写了个
@Select("select * from user where id = #{id}"),这条语句从注解到数据库返回结果,中间到底发生了什么?”
—— 所以,架构不是名词表,而是「数据与控制流的精密流水线」。
一、核心架构全景图(不是静态结构,而是动态执行链)
MyBatis 的核心不是一堆独立类,而是一条分层清晰、职责分明、可插拔的执行管道。我们按一次userMapper.selectById(1)调用的完整生命周期来串讲:
Mapper接口代理对象 ↓ (JDK动态代理拦截) SqlSession(门面 + 协调中心) ↓ (委托给内部Executor) Executor(执行器:Simple/Reuse/Batch/Caching) ↓ (封装StatementHandler + ParameterHandler + ResultSetHandler) StatementHandler(真正生成 PreparedStatement / Statement) ↓ (ParameterHandler 设置参数) JDBC PreparedStatement.execute() ↓ (ResultSetHandler 封装结果) 返回 User 对象✅关键认知:SqlSession是唯一对外暴露的入口,但它本身不干活——它像项目经理,把活分给Executor;Executor是真正的施工队长,再把SQL组装、参数绑定、结果映射等拆给更细的 Handler。
二、核心组件深度解析(带原理+易错点)
1.SqlSessionFactory:工厂中的“印钞机”
- ✅本质:线程安全的单例工厂(通常由
SqlSessionFactoryBuilder基于mybatis-config.xml和 Mapper XML 构建一次生成)。 - 🔍干了啥?
- 解析全局配置(事务管理器、数据源、别名、插件等);
- 扫描并注册所有 Mapper 接口和 XML 映射文件(注意:XML 中的
<select id="selectById">会被解析为MappedStatement对象,存入Configuration的mappedStatementsMap 中,key 是namespace.methodName,如"com.xxx.UserMapper.selectById"); - 创建
SqlSession实例(每次openSession()都新建一个非线程安全的SqlSession)。
⚠️常见误区:以为
SqlSessionFactory会缓存 SQL 执行结果?❌ 错!它只缓存元数据(MappedStatement、TypeHandler、ResultMap 等),不缓存任何业务数据。缓存是Executor层的事。
2.SqlSession:轻量级会话,但责任重大
- ✅不是连接池,也不是 JDBC Connection 包装器(Connection 由
Transaction管理); - ✅ 它持有一个
Executor实例(默认SimpleExecutor),所有 CRUD 方法最终都转成executor.query(...)或executor.update(...); - ✅自带一级缓存(Local Cache):默认开启,作用域是当前
SqlSession生命周期(即openSession()到close())。SqlSessionsession=factory.openSession();Useru1=session.selectOne("selectById",1);// 查询DB,存入一级缓存Useru2=session.selectOne("selectById",1);// 直接从一级缓存取,不查DB!
⚠️致命陷阱:在 Spring 中,若
@Service方法未加@Transactional,每次@Autowired Mapper调用都会创建新SqlSession→ 一级缓存完全失效!缓存命中率=0。
3.Executor:真正的执行引擎(含二级缓存开关)
- ✅ 三种实现:
SimpleExecutor:每次执行 new Statement(最简单,无重用);ReuseExecutor:缓存 Statement(key 是 SQL 字符串),避免重复 prepare;BatchExecutor:批量执行(addBatch()+executeBatch()),仅支持 update,不支持 select;
- ✅二级缓存(Second Level Cache)由 CachingExecutor 装饰实现:
- 开启条件:Mapper XML 中添加
<cache/>且实体类实现Serializable; - 缓存 key =
MapperId:SQL:parameter,value = 查询结果 List; - 跨 SqlSession 共享(需配合
@CacheNamespace或 XML<cache>); - ⚠️脏读风险:多个应用节点未用 Redis 等分布式缓存时,极易数据不一致!
- 开启条件:Mapper XML 中添加
4.StatementHandler:SQL 的“翻译官”与“执行员”
- ✅ 核心职责:
- 根据
MappedStatement获取 SQL(支持${}拼接 /#{}预编译); - 创建
PreparedStatement(或Statement); - 委托
ParameterHandler设置参数(如ps.setInt(1, 1)); - 委托
ResultSetHandler处理结果集(将ResultSet映射为 Java 对象,支持resultMap复杂嵌套)。
- 根据
🌟高阶理解:MyBatis 插件(Interceptor)能拦截的四大对象:
Executor、StatementHandler、ParameterHandler、ResultSetHandler—— 正是因为它们是执行链上最关键的“关卡”。
三、一句话总结架构灵魂
MyBatis 的核心架构 = “配置驱动的元数据中心(Configuration) + 分层解耦的执行流水线(SqlSession → Executor → StatementHandler → JDBC) + 可插拔的拦截扩展点(Plugin)”。
它不做 ORM 自动映射(不像 Hibernate),而是把 SQL 控制权交还给开发者,用最小侵入的方式,把 JDBC 的模板代码彻底消灭。
(字数:约 1080 字)
更多Java面试题整理:
JVM面试题
MySQL面试题
Redis面试题
Spring面试题
完整面试题库:
https://myquotego.com/html/questions?_from=csdn_123_4