MyBatis执行器与ORM特性深度解析
一、MyBatis的Executor执行器详解
1. MyBatis执行器类型
MyBatis有三种核心执行器实现,在org.apache.ibatis.executor
包中定义:
执行器类型 | 特点描述 |
---|---|
SimpleExecutor | 默认执行器,每次执行都会创建新的Statement对象 |
ReuseExecutor | 重用预处理语句(PreparedStatement),减少重复编译 |
BatchExecutor | 批量操作执行器,将多个更新操作合并批处理 |
CachingExecutor | 装饰器模式实现,为其他执行器提供二级缓存功能 |
2. 各执行器实现原理与区别
2.1 SimpleExecutor
工作原理:
每次执行update或query都会创建新的PreparedStatement
执行完毕后立即关闭Statement
优点:实现简单,无状态,线程安全
缺点:频繁创建/关闭Statement,性能开销较大
适用场景:常规单条SQL操作
2.2 ReuseExecutor
工作原理:
维护一个Statement缓存Map(key为SQL语句)
相同SQL重复使用已创建的PreparedStatement
优点:减少SQL预编译开销,提升重复SQL执行效率
缺点:需要维护Statement缓存,长时间不用的Statement不会主动关闭
适用场景:短时间内重复执行相同SQL语句
2.3 BatchExecutor
工作原理:
将多个update操作缓存起来
等待显式调用flushStatements()时批量提交
使用JDBC的addBatch()/executeBatch()机制
优点:大幅提升批量操作性能(减少网络往返)
缺点:需要手动控制批量提交时机
适用场景:批量插入、更新、删除操作
2.4 CachingExecutor
特殊性质:
装饰器模式实现,不单独使用
为其他执行器添加二级缓存功能
通过TransactionalCacheManager管理缓存事务
工作流程:
先查询二级缓存
缓存未命中时委托给被装饰的执行器执行
将结果存入缓存
3. 执行器配置与选择
配置方式(mybatis-config.xml):
xml
<settings><!-- 可选值:SIMPLE(默认), REUSE, BATCH --><setting name="defaultExecutorType" value="REUSE"/> </settings>
代码中临时切换:
java
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH); try {UserMapper mapper = session.getMapper(UserMapper.class);// 批量操作...session.commit(); } finally {session.close(); }
4. 执行器选择建议
常规CRUD:使用默认的SimpleExecutor即可
高频重复SQL:考虑使用ReuseExecutor
批量数据处理:显式使用BatchExecutor
缓存需求:配合CachingExecutor使用
二、MyBatis半自动ORM特性解析
1. ORM工具分类标准
特性 | 全自动ORM | 半自动ORM |
---|---|---|
SQL生成 | 框架自动生成 | 开发者编写 |
对象-关系映射 | 自动映射 | 显式配置 |
学习曲线 | 较陡峭 | 较平缓 |
灵活性 | 较低 | 较高 |
性能控制 | 较难优化 | 易于优化 |
典型代表 | Hibernate, JPA | MyBatis |
2. MyBatis作为半自动ORM的核心表现
SQL控制权:
开发者需要手动编写和维护SQL语句
可以精确控制每个查询的细节
支持原生SQL和动态SQL
映射配置:
需要显式定义ResultMap/ResultType
关联关系需要手动配置(嵌套查询/嵌套结果)
支持高级映射(构造函数映射、鉴别器等)
会话管理:
需要手动管理SqlSession生命周期
显式控制事务边界
延迟加载:
需要手动配置fetchType="lazy"
理解SqlSession作用域对延迟加载的影响
3. 半自动与全自动ORM的典型区别
查询示例对比:
JPA (全自动)
java
// 自动生成SQL:SELECT * FROM users WHERE name = ? List<User> users = entityManager.createQuery("SELECT u FROM User u WHERE u.name = :name", User.class).setParameter("name", "张三").getResultList();
MyBatis (半自动)
xml
<!-- 需手动编写SQL --> <select id="findByName" resultType="User">SELECT * FROM users WHERE name = #{name} </select>
java
// 执行明确映射的SQL List<User> users = sqlSession.selectList("findByName", "张三");
4. 半自动设计的优势与代价
优势:
性能可控:可优化每一句SQL
灵活性强:支持复杂查询和存储过程
过渡平滑:适合从原生JDBC迁移
技术债务少:避免全自动ORM的"魔法"行为
代价:
开发效率:需要编写更多样板代码
维护成本:SQL分散在XML/注解中
移植性:数据库方言差异需要手动处理
三、MyBatis核心理解与架构剖析
1. MyBatis架构全景图
text
[应用程序]|v [MyBatis API] (SqlSession, MapperProxy)|v [核心执行流程] |-- 配置解析|-- SQL解析|-- 参数处理|-- SQL执行|-- 结果映射|v [JDBC]
2. 核心组件与工作流程
配置阶段:
解析mybatis-config.xml全局配置
加载Mapper.xml映射文件
构建Configuration对象(包含所有配置信息)
会话阶段:
创建SqlSessionFactory
开启SqlSession(包含Executor实例)
获取Mapper接口代理对象(MapperProxy)
执行阶段:
参数处理(TypeHandler)
SQL解析(包括动态SQL)
执行查询/更新(通过Executor)
结果映射(ResultSetHandler)
缓存体系:
一级缓存(SqlSession级别)
二级缓存(Mapper级别)
3. MyBatis的核心价值主张
SQL与代码分离:
SQL保存在XML/注解中
业务代码不掺杂SQL字符串拼接
简化JDBC但不隐藏:
封装了样板代码(连接管理、结果集遍历等)
仍保持对JDBC底层访问的能力
灵活的结果映射:
支持简单POJO到复杂嵌套对象
可自定义TypeHandler处理特殊类型
插件扩展体系:
可拦截四大核心组件
实现分页、审计等通用功能
4. 适用场景分析
最适合场景:
需要高度优化SQL性能的项目
遗留数据库或复杂数据库模式
需要调用存储过程的系统
对SQL有深度控制需求的团队
不太适合场景:
快速原型开发
简单CRUD为主的应用程序
需要跨数据库移植的项目
5. MyBatis的演进趋势
注解支持增强:
@Select, @Insert等注解功能不断完善
动态SQL也可以通过@SelectProvider实现
Spring Boot整合:
MyBatis-Spring-Boot-Starter简化配置
自动发现Mapper接口
Kotlin支持:
更好的Kotlin DSL支持
协程等现代特性整合
响应式编程:
实验性的响应式MyBatis实现
集成R2DBC等响应式驱动
四、总结对比表格
执行器对比
执行器类型 | 线程安全 | Statement重用 | 批量支持 | 缓存支持 | 适用场景 |
---|---|---|---|---|---|
SimpleExecutor | 是 | 否 | 否 | 需装饰 | 常规操作 |
ReuseExecutor | 是 | 是(SQL级别) | 否 | 需装饰 | 重复SQL高频执行 |
BatchExecutor | 是 | 是 | 是 | 需装饰 | 批量插入/更新 |
CachingExecutor | 是 | 依赖被装饰者 | 依赖被装饰者 | 是 | 需要二级缓存的场景 |
ORM类型对比
特性维度 | 全自动ORM | MyBatis(半自动) |
---|---|---|
学习成本 | 较高 | 中等 |
开发效率 | 高(简单CRUD) | 中(需写SQL) |
性能优化 | 较难 | 容易 |
复杂查询支持 | 有限 | 强大 |
数据库移植性 | 好 | 需手动调整 |
社区生态 | 丰富(JPA) | 非常丰富 |