MyBatis 和 Hibernate 有什么区别?
结论先行:Hibernate 是全自动 ORM,把「表」映射成「对象」,SQL 由框架生成;MyBatis 是半自动映射框架,把「SQL」映射成「对象」,SQL 由开发者掌控。要极致可控的 SQL 与性能调优选 MyBatis,要快速开发、跨数据库移植选 Hibernate(今天更常见的是 Spring Data JPA)。
1. 两者的定位差异
Hibernate: Java 对象 ──框架生成 SQL──▶ 数据库
(你写 HQL / 操作实体,SQL 不可见)
MyBatis: 你写 SQL ──框架做参数与结果映射──▶ 数据库
(SQL 可见、可调、可移植性弱)
一个直观的区别:分页查询时,Hibernate 由方言(Dialect)拼 limit,换数据库不用改代码;MyBatis 里 limit 是你自己写的,换 Oracle 就得改成 rownum。
2. 关键维度对比
| 维度 | MyBatis | Hibernate / JPA |
|---|---|---|
| 映射方式 | SQL 与对象映射(XML/注解) | 实体与表映射(ORM) |
| SQL 控制力 | 完全掌控,可写任意 SQL | 由框架生成,调优需懂 HQL/Criteria |
| 学习曲线 | 会 SQL 就能上手 | 需理解一级/二级缓存、脏检查、延迟加载 |
| 数据库移植 | 弱,SQL 方言自己处理 | 强,靠 Dialect 适配 |
| 动态 SQL | <if>、<foreach> 原生支持 | 需 Criteria API 或 Specification |
| 性能调优 | 改 SQL、加索引,直观 | 关注 N+1、抓取策略、批量写入 |
| 缓存 | 一级/二级缓存,粒度粗 | 一级/二级缓存 + 查询缓存 |
| 适合场景 | 互联网高并发、复杂报表 SQL | 业务模型稳定、以 CRUD 为主的中后台 |
3. 同一需求的两种写法
MyBatis:SQL 与映射显式声明。
<select id="selectByStatus" resultType="com.example.Order">
SELECT id, user_id, amount, status
FROM t_order
WHERE status = #{status}
AND created_at >= #{begin}
ORDER BY id DESC
LIMIT #{offset}, #{size}
</select>
Hibernate / JPA:只描述查询意图,SQL 由框架生成。
public interface OrderRepository extends JpaRepository<Order, Long> {
// 方法名即查询语义,框架生成 SQL
List<Order> findByStatusAndCreatedAtAfterOrderByIdDesc(
OrderStatus status, LocalDateTime begin, Pageable pageable);
}
如果这条 SQL 需要用到 FORCE INDEX、窗口函数或复杂的多表聚合,JPA 就得退化到 @Query(nativeQuery = true),此时它相对 MyBatis 的优势基本消失。
4. 怎么选
- 团队 SQL 能力强、查询复杂、性能敏感:选 MyBatis,SQL 全部可审查、可 explain。
- 领域模型复杂、实体关系多、以增删改查为主:选 JPA,省掉大量样板映射。
- 已经用了 Spring Data JPA,但个别复杂查询:用
@Query或 MyBatis 混用,不必二选一。 - 不要因为「MyBatis 更火」就选它:MyBatis 把复杂度转移给了 SQL 和 XML 维护。
5. 常见追问
追问一:MyBatis 算 ORM 吗? 严格说不算。ORM 的核心是对象与表的自动映射、状态跟踪与脏检查;MyBatis 只做「SQL 结果 → 对象」的映射,不跟踪对象状态,所以被称为 SQL Mapper 或半自动 ORM。
追问二:Hibernate 的一级缓存和 MyBatis 的一级缓存一样吗? 都是 Session/SqlSession 级别,但 Hibernate 的一级缓存同时承担「持久化上下文」职责,能感知对象修改并在 flush 时自动发 UPDATE;MyBatis 的缓存只是查询结果缓存,改对象不会自动落库。
追问三:MyBatis 为什么在互联网公司更流行? 互联网业务 SQL 复杂且变化快,DBA 要求所有 SQL 可审计、可加 hint;MyBatis 的 SQL 明文写在 XML 里,评审、慢查询定位、索引优化都直接。JPA 生成的 SQL 不透明,线上出问题排查成本高。
追问四:用了 JPA 还能不能写原生 SQL?
可以,@Query(value = "...", nativeQuery = true) 或 EntityManager.createNativeQuery。但一旦大量使用原生 SQL,JPA 的移植性优势就没了,等于用 JPA 的壳写 MyBatis 的活。
小结
区别的本质是控制权放在谁手里:Hibernate 把 SQL 交给框架,换来开发效率与移植性;MyBatis 把 SQL 交回开发者,换来可控性与调优空间。选型看的是团队能力与业务查询复杂度,而不是框架本身的「先进程度」。