谈谈 Mybatis 的工作原理?
2026年01月07日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官提出这个问题,通常希望考察以下几个层面,而不仅仅是知道一个简单的流程:
- 对 MyBatis 整体架构的理解:能否宏观描述 MyBatis 如何将 JDBC 操作封装、简化,核心组件有哪些以及它们如何协作。
- 对核心工作原理的掌握深度:特别是
SqlSession、Executor、MappedStatement这几个核心对象在 一次数据库操作 中的职责与调用链。 - 对动态代理机制的应用:是否理解 MyBatis 如何通过动态代理,将我们定义的 Mapper 接口 与 XML/注解配置的 SQL 绑定起来,这是其设计精髓。
- 对配置解析和缓存机制的认识:了解配置文件的加载过程以及一级/二级缓存的工作位置和生命周期,这是性能优化和排查问题的基础。
核心答案
MyBatis 的工作原理可以概括为:通过封装 JDBC,提供了一套以 SqlSession 为核心,基于接口绑定和动态代理的数据库操作框架。
一次典型的查询操作,其核心流程如下:
- 加载配置:启动时解析
mybatis-config.xml和所有Mapper.xml文件,将配置信息(数据源、事务、SQL 语句等)构建成内存中的配置对象Configuration。 - 创建 SqlSessionFactory:用上一步的
Configuration对象创建SqlSessionFactory,它是生产SqlSession的工厂。 - 创建 SqlSession:通过
SqlSessionFactory打开一个SqlSession,它代表一次数据库会话。 - 获取 Mapper 代理对象:调用
sqlSession.getMapper(MapperInterface.class),MyBatis 会使用 动态代理 技术,为该接口生成一个代理对象。 - 执行数据库操作:调用代理对象的方法时,代理逻辑会将 方法名 和 参数 转换为对应的
MappedStatementID,并委托给SqlSession执行。SqlSession内部通过Executor(执行器)来操作数据库。Executor会先查询缓存,然后通过StatementHandler编译 SQL、设置参数,最终通过底层的JDBC执行 SQL 并获取结果。 - 结果映射:
ResultSetHandler将 JDBC 返回的ResultSet转换为 Java 对象(根据映射配置),并返回。 - 关闭会话:最终关闭
SqlSession。
深度解析
原理/机制
- 配置初始化:所有 XML 和注解配置最终被解析为
Configuration单例对象,它是 MyBatis 的 “大脑”。 - 动态代理绑定:这是关键。
Mapper接口本身没有实现类。MyBatis 利用 JDK 动态代理(或 CGLIB),为接口生成代理对象。代理类的invoke方法会拦截所有接口方法的调用,并将调用转发给SqlSession的select、insert、update、delete等方法。方法名和命名空间共同决定了要执行哪条 SQL。 - 执行器分层:
Executor是执行核心,采用职责链模式。主要有三种:SimpleExecutor(简单执行,每次新建 Statement)、ReuseExecutor(重用 Statement)、BatchExecutor(批处理)。它也是一级缓存(Local Cache)的存放地,其生命周期与SqlSession相同。 - 二级缓存:基于
Mapper命名空间,存储在Configuration对象中,生命周期与应用同步。需显式开启,并由CachingExecutor装饰器代理基础执行器来实现。
最佳实践与常见误区
#{}与${}:务必理解#{}是预编译参数占位符(防止 SQL 注入),${}是字符串替换(有注入风险,常用于动态表名/列名)。- 接口与 XML 的绑定:方法名需与 XML 中
statement的id一致,返回值类型、参数类型需匹配。 - 一级缓存:在同一个
SqlSession中,相同的查询会直接从缓存返回。但 任何 UPDATE 操作都会清空该SqlSession的一级缓存,这可能导致在事务中重复查询看不到最新数据(需理解该机制)。 - 二级缓存:分布式环境下,默认的基于 Map 的二级缓存会导致数据不一致,生产环境通常使用 Redis 等集中式缓存替代,或直接关闭二级缓存。
总结
MyBatis 的核心原理是 利用动态代理将接口调用转化为对 SqlSession 模板方法的调用,并通过 Executor、StatementHandler 等组件链式完成 SQL 准备、参数绑定、执行及结果映射,其设计精巧地平衡了灵活性(手写 SQL)、易用性(接口化)与可扩展性(插件机制)。