reuseexecutor通过map缓存statement(key为sql字符串,value为preparedstatement),复用已编译语句避免重复prepare,提升高频相同sql执行性能,缓存有效期为sqlsession生命周期。

ReuseExecutor 通过复用已编译的 Statement 对象来减少数据库驱动的解析开销,其核心是用 Map 缓存 Statement(key 为 SQL 字符串,value 为 PreparedStatement 或 CallableStatement 实例)。它不缓存结果,也不处理参数绑定逻辑,只避免重复 prepare 操作——这对执行大量相同 SQL(尤其是带不同参数的批量操作)的场景有明显收益。
ReuseExecutor 的缓存结构与触发时机
ReuseExecutor 内部维护一个 ConcurrentHashMap<string statement></string>(实际类型为 Map<string statement></string>),其中 key 是原始 SQL 字符串(未做占位符替换、不含参数值),value 是 JDBC 的 PreparedStatement 实例。
- 每次执行 SQL 前,先用 SQL 字符串查 Map;命中则直接复用该 Statement,跳过
connection.prepareStatement(sql) - 未命中则新建 Statement,并 put 进 Map,供后续同 SQL 复用
- 缓存仅在当前 Executor 生命周期内有效(如 SqlSession 关闭时,ReuseExecutor 被销毁,Map 清空)
为什么能提升性能?关键在省掉 prepare 阶段
JDBC 中 prepareStatement(sql) 会触发数据库侧的 SQL 解析、语法检查、执行计划生成(尤其对复杂查询或首次执行的语句)。这部分开销在高并发、高频次执行相同 SQL 时不可忽视。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- MySQL 的
prepare协议调用需网络往返 + 服务端解析 - Oracle 的硬解析代价更高,而 ReuseExecutor 等效于应用层“软预编译”
- 注意:MyBatis 的
#{}参数占位符不影响 SQL 字符串一致性,所以SELECT * FROM user WHERE id = ?只缓存一次,无论传入 1 还是 100
使用限制与注意事项
ReuseExecutor 不是万能加速器,适用场景有限制:
- 仅对静态 SQL(即未使用
<bind></bind>、${}拼接等导致 SQL 字符串变化的操作)有效;一旦 SQL 字符串不同(如动态表名、条件拼接),就无法命中缓存 - Statement 复用要求连接未关闭、事务未提交/回滚(否则 JDBC 驱动可能使 Statement 失效);MyBatis 在 closeStatement() 时会主动从 Map 中移除失效项
- 不适用于需要频繁切换 autocommit、fetch size、query timeout 等 Statement 属性的场景——因为复用的 Statement 属性是上一次设置的,可能不符合当前需求
- 默认不启用,需显式配置:
<setting name="defaultExecutorType" value="REUSE"></setting>或创建 SqlSessionFactory 时指定 ExecutorType.REUSE
和 SimpleExecutor、BatchExecutor 的对比
三种执行器定位不同:
- SimpleExecutor:每次执行都新建 Statement,最安全但开销最大
- ReuseExecutor:按 SQL 字符串复用 Statement,平衡性能与兼容性
- BatchExecutor:基于 JDBC batch API 批量提交(addBatch + executeBatch),适合大批量 insert/update,但仅支持无返回值的更新操作,且 Statement 复用逻辑更复杂(依赖 batchKey)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










