MyBatis BaseExecutor 模板方法模式与策略模式详解
📌 MyBatis BaseExecutor 模板方法模式与策略模式详解
BaseExecutor 是 MyBatis Executor 体系的核心抽象类,它通过模板方法模式(Template Method Pattern)定义查询和更新的执行骨架,通过策略模式(Strategy Pattern)动态切换 SimpleExecutor、ReuseExecutor、BatchExecutor 三种执行策略。面试中经常被问到:"MyBatis 用了哪些设计模式?" BaseExecutor 就是模板方法模式与策略模式结合的经典案例。
1️⃣ 问题背景
在 MyBatis 中,所有 SQL 最终都会被 Executor 执行。
例如:
或者:
这些 SQL 的执行逻辑其实非常类似:
- 创建 Statement
- 参数绑定
- 执行 SQL
- 结果集映射
- 缓存处理
- 事务控制
如果每种 Executor 都重复实现这些流程,将会出现大量重复代码。
同时,不同 Executor 的执行方式又有所不同:
- SimpleExecutor 每次创建新 Statement
- ReuseExecutor 复用 Statement
- BatchExecutor 支持批量提交
因此 MyBatis 需要一种设计:
这正是模板方法模式和策略模式发挥作用的地方。
2️⃣ 核心原理
Executor继承体系
│
├── BaseExecutor
│ │
│ ├── SimpleExecutor
│ ├── ReuseExecutor
│ └── BatchExecutor
│
└── CachingExecutor
Executor 是顶层接口。
BaseExecutor 实现大部分通用逻辑。
SimpleExecutor、ReuseExecutor、BatchExecutor 负责实现差异化逻辑。
CachingExecutor 则属于装饰器模式,在 Executor 外层增加二级缓存功能。
3️⃣ 数据结构分析
BaseExecutor核心属性
其中:
- Transaction:事务对象
- localCache:一级缓存
- localOutputParameterCache:存储存储过程参数
- Configuration:全局配置
- queryStack:嵌套查询层级
一级缓存结构
BaseExecutor 内部维护一级缓存 HashMap。
同一个 SqlSession 内重复查询时直接返回缓存结果。
4️⃣ 算法分析
BaseExecutor查询算法
query() 方法执行过程:
│
├── 创建CacheKey
├── 查询一级缓存
├── 命中直接返回
│
└── 未命中
│
▼
queryFromDatabase()
│
▼
doQuery()
时间复杂度:
- 缓存命中:O(1)
- 缓存未命中:O(SQL执行时间)
由于优先查缓存,大多数业务场景可以显著减少数据库访问次数。
5️⃣ 执行流程
模板方法模式分析
BaseExecutor 中最经典的方法:
clearLocalCache();
return doUpdate(...);
}
这里 update() 已经固定了执行流程:
- 清空缓存
- 执行更新
而具体如何更新,交给子类实现:
再看 query():
查询一级缓存
缓存未命中
queryFromDatabase()
}
最终执行:
该方法由子类实现。
模板方法模式特点
子类实现具体步骤
流程不可修改
细节可以扩展
这就是标准模板方法模式。
6️⃣ 实际案例
SimpleExecutor
每次执行 SQL 都创建新的 Statement。
createStatement()
查询2
createStatement()
特点:
- 实现简单
- 资源占用低
- 频繁创建对象
ReuseExecutor
内部维护 StatementMap。
SQL2 → Statement2
再次执行相同 SQL:
减少数据库资源消耗。
BatchExecutor
适用于批量插入场景。
insert user2
insert user3
insert user4
flushStatements()
统一提交到数据库。
性能提升非常明显。
7️⃣ 优缺点分析
✅ 模板方法模式优点
- 消除重复代码
- 统一执行流程
- 提高扩展能力
- 符合开闭原则
- 降低维护成本
❌ 模板方法模式缺点
- 继承层次较深
- 父类职责较重
- 修改模板影响所有子类
✅ 策略模式优点
- 执行策略灵活切换
- 避免大量if else
- 扩展新Executor简单
- 符合单一职责原则
❌ 策略模式缺点
- 类数量增加
- 调用链更复杂
8️⃣ 面试常见问题
BaseExecutor用了什么设计模式?
为什么说BaseExecutor是模板方法模式?
因为:
- update()定义固定流程
- query()定义固定流程
- doUpdate()交给子类实现
- doQuery()交给子类实现
符合:
延迟部分实现到子类
为什么说Executor用了策略模式?
Executor接口定义统一行为:
- update()
- query()
- commit()
- rollback()
具体执行策略:
- SimpleExecutor
- ReuseExecutor
- BatchExecutor
运行时可以自由切换。
Executor默认实现是哪一个?
MyBatis 默认创建 SimpleExecutor。
CachingExecutor属于什么模式?
属于装饰器模式(Decorator Pattern)。
其作用是在 Executor 外层增加二级缓存能力。
MyBatis还有哪些经典设计模式?
- 工厂模式(SqlSessionFactory)
- 代理模式(MapperProxy)
- 模板方法模式(BaseExecutor)
- 策略模式(Executor)
- 装饰器模式(CachingExecutor)
- 建造者模式(XMLConfigBuilder)
- 责任链模式(InterceptorChain)
- 适配器模式(LogAdapter)
9️⃣ 总结
📌 BaseExecutor是MyBatis执行器体系核心抽象类。
📌 模板方法模式:BaseExecutor定义query()、update()等固定执行流程,doQuery()、doUpdate()交给子类实现。
📌 策略模式:SimpleExecutor、ReuseExecutor、BatchExecutor代表三种不同SQL执行策略,运行时动态切换。
📌 SimpleExecutor:每次创建新Statement。
📌 ReuseExecutor:复用Statement减少资源开销。
📌 BatchExecutor:批量执行SQL提升吞吐量。
📌 CachingExecutor:使用装饰器模式增强Executor,实现二级缓存功能。
📌 面试高频总结:MyBatis执行器体系是模板方法模式与策略模式结合的经典案例。BaseExecutor负责定义执行骨架,SimpleExecutor、ReuseExecutor、BatchExecutor负责提供不同执行策略,这种设计既保证了代码复用,又保证了扩展灵活性,是框架源码设计中的典型范例。
相关文章
-
微服务如何拆分?
以后如果从0到1开展微服务工作,那么微服务如何拆分是必须要学会的,今天就详细聊一下微服务如何拆分。(本篇文章参考李运华的4R架构)
NEW个对象 2024-10-05
-
MySQL索引:聚集索引、非聚集索引、联合索引、回表、索引覆盖
MySQL索引:聚集索引、非聚集索引、联合索引、回表、索引覆盖
NEW个对象 2024-10-03
-
面试官让我设计一个秒杀系统
秒杀系统需要解决哪些问题,这里列几个关键性的问题: 1、高并发的瞬时流量 2、库存扣减 3、重复下单 4、热点数据
NEW个对象 2024-10-07