Mybatis 都有哪些 Executor 执行器?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 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 核心执行引擎的掌握深度。面试官不仅仅是问 “有哪些”,更想了解:

  1. 源码级别的理解:是否清楚每种执行器对应的具体实现类及其在源码中的组织方式。
  2. 配置与实现的映射关系:能否区分 “配置值”(SIMPLE)和 “实现类”(SimpleExecutor)的不同含义及它们如何关联。
  3. 核心工作机制差异:重点考察对三种执行器在 Statement 管理策略上的根本区别的理解。
  4. 架构设计模式的应用:是否理解 CachingExecutor 作为装饰器的设计模式应用及其与基础执行器的关系。
  5. 实践调优能力:能否根据不同业务场景(高频查询 vs 批量写入)选择合适的执行器进行性能优化。

核心答案

MyBatis 有三种核心的 Executor 实现类和一种装饰器类:

1. 核心实现类:

  • SimpleExecutor:默认执行器,每次执行都创建新的 PreparedStatement
  • ReuseExecutor:重用执行器,缓存相同的 SQL 对应的 PreparedStatement
  • BatchExecutor:批处理执行器,将多个更新操作合并批量执行。

2. 装饰器类:

  • CachingExecutor:二级缓存装饰器,为上述任意执行器添加缓存功能。

在配置时,我们使用对应的 ExecutorType 枚举值:SIMPLEREUSEBATCH,MyBatis 会根据这些值实例化相应的类。

深度解析

类名与配置值的映射机制

这是理解 MyBatis 执行器的关键。SimpleExecutorReuseExecutorBatchExecutor具体的实现类,位于 org.apache.ibatis.executor 包中。而我们在配置中使用的 SIMPLEREUSEBATCHExecutorType 枚举的常量值,它们通过一个简单的工厂逻辑映射到具体的类:

// 简化版源码逻辑(org.apache.ibatis.session.Configuration)
public Executor newExecutor(ExecutorType executorType) {
    Executor executor;
    switch (executorType) {
        case BATCH:
            executor = new BatchExecutor(this, transaction);
            break;
        case REUSE:
            executor = new ReuseExecutor(this, transaction);
            break;
        default: // 包括 SIMPLE 和未指定时
            executor = new SimpleExecutor(this, transaction);
            break;
    }
    // 如果开启了二级缓存,用 CachingExecutor 进行包装
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
    return executor;
}

三种核心执行器的核心区别

执行器核心机制Statement 管理策略适用场景
SimpleExecutor每次执行新建执行后立即关闭通用场景,默认选择
ReuseExecutorSQL 语句级缓存缓存相同 SQL 的 Statement,会话结束时关闭短时内高频执行相同 SQL
BatchExecutor批量操作累积缓存更新操作的 Statement,手动触发执行大批量数据写入或更新

CachingExecutor 的特殊角色

不是与前三者并列的第四种执行器,而是装饰器模式的典型应用。当 MyBatis 配置中开启二级缓存时,会自动用 CachingExecutor 包装你选择的实际执行器:

  • 结构CachingExecutor 持有 delegate(可能是 SimpleExecutorReuseExecutorBatchExecutor
  • 行为:执行查询时,先查二级缓存 → 命中则返回 → 未命中则委托给 delegate 执行数据库查询 → 结果存入二级缓存

配置与使用示例

<!-- mybatis-config.xml 中配置默认执行器类型 -->
<settings>
    <!-- 注意这里写的是枚举值,不是类名 -->
    <setting name="defaultExecutorType" value="BATCH"/>
</settings>
// 编程式指定执行器类型(优先级高于配置)
try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    for (int i = 0; i < 1000; i++) {
        mapper.insert(new User("user" + i));
    }
    // 必须显式提交,BatchExecutor 才会执行批量操作
    session.commit();
}

常见误区与最佳实践

  • 误区1:认为 CachingExecutor 是独立的基础执行器。实际上它只是装饰层。
  • 误区2:在 BatchExecutor 中忘记调用 commit()flushStatements(),导致操作未执行。
  • 误区3:在任何场景下都使用 ReuseExecutor。实际上长时间不关闭的 SqlSession 使用 ReuseExecutor 可能导致 Statement 缓存泄漏。
  • 最佳实践:常规业务使用默认的 SimpleExecutor;数据导入等场景使用 BatchExecutor;只有确认存在大量相同 SQL 重复执行时,才考虑使用 ReuseExecutor

总结

理解 MyBatis 执行器的关键是:区分配置枚举(SIMPLE)与实现类(SimpleExecutor)的对应关系,掌握三种基础执行器对 Statement 的不同管理策略,并明确 CachingExecutor 作为装饰器的特殊角色。这在面试中能体现出对 MyBatis 架构设计的深入理解。