MyBatis 提供了四种执行器(Executor),分别针对不同的场景优化 SQL 执行效率。以下是每种执行器的详细解释及最佳实践:
1. SimpleExecutor:简单场景
-
工作机制
- 默认执行器,每次执行 SQL 时创建新的
Statement对象,执行后立即关闭。 - 不缓存任何资源,确保每次操作都是独立的。
- 默认执行器,每次执行 SQL 时创建新的
-
适用场景
- 单次查询或更新操作。
- 不需要复用 SQL 或批量处理的常规场景。
-
最佳实践
- 无需特殊配置:MyBatis 默认使用
SimpleExecutor,适合大多数简单操作。 - 避免循环中的频繁调用:若在循环中重复执行相同 SQL,应切换至
ReuseExecutor以提升性能。
- 无需特殊配置:MyBatis 默认使用
示例代码:
// 默认使用 SimpleExecutor
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
}
2. ReuseExecutor:高频重复 SQL
-
工作机制
- 复用
PreparedStatement对象,根据 SQL 语句缓存已编译的PreparedStatement。 - 相同 SQL 的多次执行共享同一
PreparedStatement,减少数据库编译开销。
- 复用
-
适用场景
- 高频执行相同 SQL(如循环中多次查询)。
- SQL 参数类型和顺序固定的场景。
-
最佳实践
- 启用方式:通过配置或代码指定执行器类型为
REUSE。 - 注意 SQL 一致性:SQL 必须完全相同(包括空格和参数顺序),否则无法复用。
- 避免内存泄漏:及时关闭
SqlSession,防止缓存的PreparedStatement长期占用资源。
- 启用方式:通过配置或代码指定执行器类型为
配置方式:
<settings>
<setting name="defaultExecutorType" value="REUSE"/>
</settings>
示例代码:
try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.REUSE)) {
UserMapper mapper = session.getMapper(UserMapper.class);
for (int i = 0; i < 1000; i++) {
User user = mapper.selectUserById(i); // 相同 SQL 复用 PreparedStatement
}
}
3. BatchExecutor:批量操作
-
工作机制
- 批量模式:将多个更新操作(如
INSERT/UPDATE/DELETE)缓存到Statement队列,最后一次性提交。 - 显著减少数据库交互次数,提升批量操作性能。
- 批量模式:将多个更新操作(如
-
适用场景
- 批量插入、更新或删除(如导入数据、批量更新状态)。
-
最佳实践
- 显式提交事务:批量操作后必须调用
commit(),否则数据不会持久化。 - 合理控制批量大小:避免单次批量操作数据量过大导致内存溢出。
- 资源释放:操作完成后及时关闭
SqlSession。
- 显式提交事务:批量操作后必须调用
示例代码:
try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
UserMapper mapper = session.getMapper(UserMapper.class);
for (User user : userList) {
mapper.insertUser(user); // 添加至批处理队列
}
session.commit(); // 必须显式提交!
}
4. CachingExecutor:二级缓存支持
-
工作机制
- 装饰器模式:包裹其他执行器(如
SimpleExecutor),为其添加二级缓存功能。 - 优先从缓存读取数据,未命中时委托底层执行器查询数据库,并将结果缓存。
- 装饰器模式:包裹其他执行器(如
-
适用场景
- 读多写少的数据(如配置信息、静态数据)。
- 允许一定时间的数据不一致性。
-
最佳实践
- 启用缓存:在 Mapper XML 中添加
<cache/>标签。 - 序列化要求:实体类需实现
Serializable接口。 - 缓存失效:更新操作自动清除相关缓存,避免脏读。
- 分布式缓存:集群环境下建议集成 Redis 或 Ehcache。
- 启用缓存:在 Mapper XML 中添加
配置方式:
<!-- UserMapper.xml -->
<mapper namespace="com.example.UserMapper">
<cache/> <!-- 启用二级缓存 -->
<select id="selectUserById" resultType="User">...</select>
</mapper>
示例代码:
// 第一次查询(缓存未命中,从数据库读取)
User user1 = userMapper.selectUserById(1);
// 第二次查询(直接读取缓存)
User user2 = userMapper.selectUserById(1);
总结:执行器选择建议
| 执行器 | 适用场景 | 性能优化点 |
|---|---|---|
| SimpleExecutor | 简单单次操作 | 默认配置,无需额外处理。 |
| ReuseExecutor | 高频重复 SQL | 减少 PreparedStatement 编译开销。 |
| BatchExecutor | 批量写操作 | 减少数据库交互次数。 |
| CachingExecutor | 读多写少,允许缓存 | 减少数据库查询压力。 |
通用最佳实践:
- 根据业务场景灵活选择执行器类型。
- 批量操作后务必显式提交事务。
- 高频查询场景合理使用二级缓存,但注意缓存一致性。
- 生产环境中监控执行器性能,及时调整配置。