MyBatis 架构与核心组件全解析:从三层架构到 SQL 执行链路
MyBatis 的架构设计清晰且模块化,通过 基础支持层、核心处理层、接口层 三层结构实现 “配置驱动、插件可扩展、低侵入” 的特性。本文深入拆解每一层的核心组件、职责及协作关系,并结合 SQL 执行全链路,帮你理解 MyBatis 如何将 “配置” 转化为 “数据库操作”,构建完整的技术认知。
MyBatis 三层架构总览
MyBatis 的三层架构并非物理隔离,而是按 “职责划分” 的逻辑分层,各层组件协同工作,形成从 “接口调用” 到 “数据库响应” 的闭环。三层的核心职责与组件对应关系如下:
| 架构分层 | 核心职责 | 关键组件 |
|---|---|---|
| 接口层 | 提供对外 API,简化开发者调用 | SqlSession、MapperProxy(动态代理) |
| 核心处理层 | 实现 SQL 执行与结果映射的核心逻辑 | Executor(执行器)、StatementHandler(SQL 处理器)、ParameterHandler(参数处理器)、ResultSetHandler(结果处理器)、Configuration(配置中心) |
| 基础支持层 | 为核心层提供通用支撑能力,保证框架稳定性 | 数据源、事务管理、日志、类型转换(TypeHandler)、缓存、XML/OGNL 解析器 |
分层详解:组件职责与协作
1. 基础支持层:框架的 “地基”
基础支持层是 MyBatis 的 “工具集”,为核心处理层提供通用能力,不直接参与 SQL 执行,但决定了框架的扩展性、稳定性和性能。
(1)核心组件与职责
| 组件 | 核心职责 | 关键实现 / 配置 |
|---|---|---|
| 数据源(DataSource) | 管理数据库连接,优化连接复用 | - 内置实现:UnpooledDataSource(无池)、PooledDataSource(有池); - 第三方集成:HikariCP(Spring Boot 默认)、Druid(阿里) |
| 事务管理(Transaction) | 管理事务生命周期(提交 / 回滚 / 关闭) | - 内置类型:JdbcTransaction(依赖 JDBC 事务)、ManagedTransaction(交给容器管理); - 由 TransactionFactory 工厂创建 |
| 日志(Logging) | 打印 SQL 执行日志,便于调试 | 适配主流日志框架:SLF4J、Log4j2、Commons Logging、JDK Logging;通过 logImpl 配置 |
| 类型转换(TypeHandler) | 实现 Java 类型 ↔ JDBC 类型的双向转换 | - 内置类型:StringTypeHandler、IntegerTypeHandler 等(覆盖常用类型); - 自定义扩展:实现 TypeHandler 接口(如 LocalDateTimeTypeHandler) |
| 缓存(Cache) | 提供二级缓存支持,减少数据库访问 | - 内置实现:PerpetualCache(内存缓存)、LruCache(LRU 回收); - 第三方集成:Redis、EHCache(实现 Cache 接口) |
| 解析器(Parser) | 解析 XML 配置、OGNL 表达式、SQL 语句 | - XMLConfigBuilder(全局配置解析)、XMLMapperBuilder(Mapper 解析); - XPathParser(XML 节点解析)、OGNLExpressionEvaluator(OGNL 表达式计算) |
| 反射工具(Reflector) | 优化 Java 反射性能,简化属性访问 | ReflectorFactory 生成 Reflector 对象,缓存类的属性、方法信息,避免重复反射 |
(2)核心作用
- 解耦通用能力:将数据源、事务、日志等通用功能抽象为独立组件,核心层无需关注细节(如连接池实现);
- 扩展灵活性:支持第三方组件替换(如用 Druid 替换内置数据源),通过配置即可生效,无需修改核心代码。
2. 核心处理层:SQL 执行的 “引擎”
核心处理层是 MyBatis 的 “大脑”,负责将 “配置信息” 转化为 “实际 SQL 执行”,并完成结果映射。这一层的组件是 MyBatis 最核心的逻辑载体。
(1)核心组件与职责(按 SQL 执行流程排序)
① Configuration:全局配置中心
- 职责:存储所有配置信息(全局设置、数据源、Mapper 映射、插件等),是 MyBatis 初始化的最终产物,贯穿整个框架生命周期;
- 核心内容:
mappedStatements:存储所有MappedStatement(封装单条 SQL 的元数据,如 SQL 语句、参数类型、结果类型);resultMaps:存储所有ResultMap(结果映射规则,解决字段与属性名不一致);environment:存储数据库环境(数据源 + 事务管理器);plugins:存储注册的插件(拦截器链)。
- 地位:所有核心组件(
Executor、StatementHandler等)的创建都依赖Configuration,是组件协作的 “数据中枢”。
② Executor:执行器(SQL 调度核心)
职责:MyBatis 的 “执行调度中心”,负责协调
StatementHandler、ParameterHandler、ResultSetHandler完成 SQL 执行,同时管理一级缓存和事务;核心类型(根据execType配置):
| 执行器类型 | 特点 | 适用场景 |
| ————————- | —————————————————————- | ——————————————— |
|SimpleExecutor| 默认实现,每次执行 SQL 都创建新Statement| 单条 SQL 执行(大多数场景) |
|ReuseExecutor| 复用Statement(按 SQL 缓存) | 重复执行相同 SQL(如循环查询) |
|BatchExecutor| 批量执行 SQL(仅支持 INSERT/UPDATE/DELETE) | 批量操作(如批量插入) |
|CachingExecutor| 装饰器模式,添加二级缓存支持 | 开启二级缓存时自动生效 |核心流程:
- 接收
SqlSession的请求(如selectOne); - 从
Configuration中获取MappedStatement; - 创建
StatementHandler并委托其执行 SQL; - 管理一级缓存(查询前查缓存,查询后写缓存)。
- 接收
③ StatementHandler:SQL 执行处理器(与数据库交互)
职责:直接与数据库交互,负责创建
Statement(JDBC 对象)、预编译 SQL、执行 SQL 并返回ResultSet,是 “承上启下” 的关键组件;核心类型(根据statementType配置):
| 处理器类型 | 对应 JDBC 对象 | 特点 |
| ————————————— | —————————- | —————————————————— |
|SimpleStatementHandler|Statement| 无参数 SQL(不支持?占位符) |
|PreparedStatementHandler|PreparedStatement| 预编译 SQL(支持参数占位符,防注入) |
|CallableStatementHandler|CallableStatement| 调用存储过程(支持IN/OUT参数) |核心流程:
- 从
Executor接收MappedStatement和参数; - 调用
Connection.prepareStatement()预编译 SQL; - 委托
ParameterHandler设置 SQL 参数; - 执行 SQL(
executeQuery()/executeUpdate()),返回ResultSet; - 委托
ResultSetHandler处理结果。
- 从
④ ParameterHandler:参数处理器
- 职责:将 Mapper 方法的参数(如
user.getId())映射到预编译 SQL 的?占位符,解决 “Java 参数 → JDBC 参数” 的类型转换; - 核心逻辑:
- 从
BoundSql中获取参数映射列表(parameterMappings,记录参数名、Java 类型、JDBC 类型); - 通过
TypeHandler将 Java 参数值转换为 JDBC 类型(如LocalDateTime→Timestamp); - 调用
PreparedStatement.setXxx()方法设置参数(如setInt()、setString())。
- 从
- 注意:MyBatis 内置的
DefaultParameterHandler已覆盖 99% 的场景,无需自定义,除非有特殊类型转换需求。
⑤ ResultSetHandler:结果集处理器
- 职责:将 JDBC 的
ResultSet(数据库返回结果)解析为 Java 实体类(或 List/Map),解决 “JDBC 结果 → Java 对象” 的映射; - 核心逻辑:
- 从
MappedStatement中获取ResultMap(结果映射规则); - 遍历
ResultSet的每一行数据; - 根据
ResultMap匹配 “数据库列名 → 实体属性名”,通过TypeHandler转换类型(如Timestamp→LocalDateTime); - 调用实体类的
setter方法设置属性,或通过构造器注入(constructor映射); - 处理关联查询(
association/collection):触发嵌套查询或解析嵌套结果。
- 从
- 关键能力:支持自动映射(
autoMapping)、驼峰命名映射(mapUnderscoreToCamelCase)、复杂关联映射,是 MyBatis 结果处理的核心。
⑥ Plugin:插件(拦截器)
- 职责:基于代理模式,拦截核心组件的方法(如
Executor.query()、StatementHandler.prepare()),实现功能增强(如分页、日志、性能监控); - 核心原理:
- 插件实现
Interceptor接口,通过@Signature注解指定拦截的组件和方法; - MyBatis 初始化时,将插件注册到
Configuration.plugins; - 创建核心组件(如
Executor)时,通过Plugin.wrap()生成代理对象; - 调用组件方法时,触发插件的
intercept()方法,执行增强逻辑。
- 插件实现
- 常见应用:PageHelper 分页插件(拦截
Executor.query()改写 SQL)、日志插件(拦截StatementHandler打印 SQL)。
3. 接口层:开发者的 “入口”
接口层是 MyBatis 对外暴露的 API,旨在简化开发者调用,屏蔽底层复杂逻辑(如 Executor、StatementHandler 的协作)。
(1)核心组件与职责
① SqlSession:数据库会话
- 职责:相当于 JDBC 的
Connection,代表一次数据库会话,提供 CRUD 方法(selectOne、insert、update、delete),是开发者直接操作的入口; - 核心实现:
DefaultSqlSession(默认实现),持有Configuration和Executor,将方法调用委托给Executor; - 生命周期:单次业务请求(线程不安全,需及时关闭,避免连接泄漏)。
② MapperProxy:Mapper 接口动态代理
- 职责:MyBatis 不要求开发者实现 Mapper 接口,而是通过 JDK 动态代理生成
MapperProxy对象,将 Mapper 方法调用转发给SqlSession; - 核心逻辑:
- 调用 Mapper 方法(如
userMapper.selectById(1))时,触发MapperProxy.invoke(); - 解析方法信息(如
namespace + methodName),找到对应的MappedStatement; - 调用
SqlSession的对应方法(如sqlSession.selectOne()),完成 SQL 执行;
- 调用 Mapper 方法(如
- 优势:无侵入式开发,开发者只需定义 Mapper 接口和 XML,无需编写实现类。
SQL 执行全链路:三层组件协作实战
以 “调用 userMapper.selectById(1) 查询用户” 为例,完整拆解三层组件的协作流程,理解 MyBatis 如何将 “接口调用” 转化为 “数据库响应”:
1. 链路总览
2. 关键步骤拆解(结合组件职责)
步骤 1:接口调用触发动态代理
- 开发者注入
UserMapper接口,实际注入的是MapperProxy代理对象; - 调用
userMapper.selectById(1)时,触发MapperProxy.invoke()方法。
步骤 2:解析方法并委托 SqlSession
MapperProxy解析方法的namespace(com.xxx.UserMapper)和methodName(selectById),拼接为MappedStatement的id(com.xxx.UserMapper.selectById);- 调用
sqlSession.selectOne("com.xxx.UserMapper.selectById", 1),将请求委托给SqlSession。
步骤 3:Executor 调度核心组件
SqlSession(DefaultSqlSession)调用executor.query(ms, parameter, rowBounds, resultHandler);Executor(如CachingExecutor)先查询二级缓存,未命中则调用SimpleExecutor的query();SimpleExecutor创建StatementHandler(PreparedStatementHandler),并传入MappedStatement和参数。
步骤 4:StatementHandler 与数据库交互
StatementHandler.prepare(connection):调用Connection.prepareStatement("SELECT * FROM user WHERE id = ?"),预编译 SQL;StatementHandler.parameterize(statement):委托ParameterHandler调用preparedStatement.setInt(1, 1),设置参数;StatementHandler.query(statement, resultHandler):执行preparedStatement.executeQuery(),获取ResultSet。
步骤 5:ResultSetHandler 封装结果
ResultSetHandler.handleResultSets(statement):遍历ResultSet,根据ResultMap规则(如id→id,user_name→userName),通过TypeHandler转换类型;- 创建
User对象,调用setter方法设置属性,返回User列表。
步骤 6:缓存与结果返回
Executor将查询结果写入一级缓存(LocalCache);- 结果逐层返回:
Executor→SqlSession→MapperProxy→ 开发者。
架构设计亮点与启示
- 模块化与职责单一:三层架构清晰划分职责(基础支持层负责通用能力,核心层负责 SQL 逻辑,接口层负责易用性),便于维护和扩展;
- 插件化设计:通过代理模式支持插件拦截核心组件,无需修改源码即可增强功能(如分页、日志),满足个性化需求;
- 配置驱动:所有核心逻辑基于
Configuration配置动态生成,无需硬编码(如数据源、SQL 语句、结果映射),灵活性高; - 低侵入与易用性:通过动态代理屏蔽底层细节,开发者只需定义 Mapper 接口和 XML,即可完成数据库操作,降低学习成本。
总结
MyBatis 的架构是 “简单与强大” 的平衡体:三层架构确保核心逻辑的稳定性和扩展性,核心组件(Executor、StatementHandler 等)的协作实现 SQL 执行的全流程,接口层的动态代理简化开发者调用

v1.3.10