首页 > 项目 > 当前页面

MyBatis BaseExecutor 模板方法模式与策略模式详解

2026-06-14 NEW个对象

📌 MyBatis BaseExecutor 模板方法模式与策略模式详解

核心结论:
BaseExecutor 是 MyBatis Executor 体系的核心抽象类,它通过模板方法模式(Template Method Pattern)定义查询和更新的执行骨架,通过策略模式(Strategy Pattern)动态切换 SimpleExecutor、ReuseExecutor、BatchExecutor 三种执行策略。面试中经常被问到:"MyBatis 用了哪些设计模式?" BaseExecutor 就是模板方法模式与策略模式结合的经典案例。

1️⃣ 问题背景

在 MyBatis 中,所有 SQL 最终都会被 Executor 执行。

例如:

select * from user where id = 1

或者:

update user set name='Tom' where id=1

这些 SQL 的执行逻辑其实非常类似:

  • 创建 Statement
  • 参数绑定
  • 执行 SQL
  • 结果集映射
  • 缓存处理
  • 事务控制

如果每种 Executor 都重复实现这些流程,将会出现大量重复代码。

同时,不同 Executor 的执行方式又有所不同:

  • SimpleExecutor 每次创建新 Statement
  • ReuseExecutor 复用 Statement
  • BatchExecutor 支持批量提交

因此 MyBatis 需要一种设计:

既能够统一执行流程,又能够灵活替换执行策略。

这正是模板方法模式和策略模式发挥作用的地方。


2️⃣ 核心原理

Executor继承体系

Executor

├── BaseExecutor
│ │
│ ├── SimpleExecutor
│ ├── ReuseExecutor
│ └── BatchExecutor

└── CachingExecutor

Executor 是顶层接口。

BaseExecutor 实现大部分通用逻辑。

SimpleExecutor、ReuseExecutor、BatchExecutor 负责实现差异化逻辑。

CachingExecutor 则属于装饰器模式,在 Executor 外层增加二级缓存功能。

BaseExecutor 负责定义流程,子类负责实现细节,这正是模板方法模式的典型特征。

3️⃣ 数据结构分析

BaseExecutor核心属性

protected Transaction transaction; protected PerpetualCache localCache; protected PerpetualCache localOutputParameterCache; protected Configuration configuration; protected int queryStack;

其中:

  • Transaction:事务对象
  • localCache:一级缓存
  • localOutputParameterCache:存储存储过程参数
  • Configuration:全局配置
  • queryStack:嵌套查询层级

一级缓存结构

CacheKey │ ▼ MappedStatement SQL 参数 分页信息 Environment │ ▼ ResultObject

BaseExecutor 内部维护一级缓存 HashMap。

同一个 SqlSession 内重复查询时直接返回缓存结果。


4️⃣ 算法分析

BaseExecutor查询算法

query() 方法执行过程:

query()

├── 创建CacheKey
├── 查询一级缓存
├── 命中直接返回

└── 未命中


queryFromDatabase()


doQuery()

时间复杂度:

  • 缓存命中:O(1)
  • 缓存未命中:O(SQL执行时间)

由于优先查缓存,大多数业务场景可以显著减少数据库访问次数。


5️⃣ 执行流程

模板方法模式分析

BaseExecutor 中最经典的方法:

public int update(...) {
  clearLocalCache();
  return doUpdate(...);
}

这里 update() 已经固定了执行流程:

  • 清空缓存
  • 执行更新

而具体如何更新,交给子类实现:

protected abstract int doUpdate(...)

再看 query():

public List query(...) {
  查询一级缓存
  缓存未命中
  queryFromDatabase()
}

最终执行:

doQuery(...)

该方法由子类实现。

模板方法模式特点

父类定义算法骨架
子类实现具体步骤
流程不可修改
细节可以扩展

这就是标准模板方法模式。


6️⃣ 实际案例

SimpleExecutor

每次执行 SQL 都创建新的 Statement。

查询1
createStatement()

查询2
createStatement()

特点:

  • 实现简单
  • 资源占用低
  • 频繁创建对象

ReuseExecutor

内部维护 StatementMap。

SQL1 → Statement1
SQL2 → Statement2

再次执行相同 SQL:

直接复用Statement

减少数据库资源消耗。

BatchExecutor

适用于批量插入场景。

insert user1
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默认实现是哪一个?

SimpleExecutor

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负责提供不同执行策略,这种设计既保证了代码复用,又保证了扩展灵活性,是框架源码设计中的典型范例。

相关文章

NEW个对象 NEW个对象
JAVA是世界上最好的语言