SimpleExecutor每次执行都新建并关闭PreparedStatement,适合动态SQL和调试;ReuseExecutor按SQL字符串缓存复用PreparedStatement,提升重复SQL执行效率,适用于高QPS、模板固定场景。

MyBatis 的 SimpleExecutor 和 ReuseExecutor 是两种不同行为模式的 SQL 执行器,差异核心在于 PreparedStatement 是否复用,这直接影响 JDBC 层的资源开销与执行效率。它们不改变 SQL 语义或结果,只影响底层 Statement 的生命周期管理。
SimpleExecutor:每次执行都新建 PreparedStatement
这是 MyBatis 默认执行器。每调用一次 sqlSession.selectOne() 或 update(),都会:
- 调用 JDBC
Connection.prepareStatement(sql)创建全新 PreparedStatement 实例 - 设置参数、执行、获取结果
- 立即调用
statement.close()释放资源
优点是逻辑清晰、无状态残留,适合单次、异构 SQL 场景;缺点是频繁 prepare 带来额外开销(尤其高并发下连接池压力明显)。例如连续执行 SELECT * FROM user WHERE id = ? 10 次,会生成并关闭 10 个独立 PreparedStatement。
ReuseExecutor:按 SQL 字符串缓存并复用 PreparedStatement
它在 SqlSession 生命周期内维护一个 Map<string preparedstatement></string>,以原始 SQL(不含参数值)为 key:
立即学习“Java免费学习笔记(深入)”;
- 首次执行某条 SQL 时,创建 PreparedStatement 并放入 map
- 后续相同 SQL(如同样模板的
SELECT * FROM order WHERE status = ?)直接从 map 取出已编译对象 - 仅重置参数(
setInt(1, 2)等),跳过重复 prepare 步骤 - SqlSession 关闭或事务结束时,统一关闭所有缓存的 PreparedStatement
注意:SQL 字符串必须完全一致(含空格、换行、别名),否则视为不同 key。比如 "SELECT id FROM t" 和 "SELECT id FROM t" 会被当作两条语句分别缓存。
如何切换使用 ReuseExecutor
不能全局强制替换默认执行器(不推荐 XML 配置 <setting name="defaultExecutorType" value="REUSE"/>),应按需局部指定:
- 创建 SqlSession 时传参:
sqlSessionFactory.openSession(ExecutorType.REUSE) - 该 SqlSession 内所有操作均走 ReuseExecutor,无需修改 Mapper 接口或 XML
- 若同时需批量更新,应改用
ExecutorType.BATCH,ReuseExecutor 不处理 addBatch
实际选型建议
不用纠结“哪个更好”,而要看场景特征:
- 读多写少、SQL 模板高度重复(如分页查询固定表)、QPS 较高 → ReuseExecutor 更合适
- 动态 SQL 多(
<if>嵌套导致每次 SQL 字符串不同)、短生命周期 SqlSession、调试阶段 → SimpleExecutor 更稳妥 - 两者都依赖一级缓存机制,但缓存命中与否与 Executor 类型无关,只取决于查询条件和 SqlSession 状态


















