MyBatis 与 JPA/Hibernate 对比与选型
写 Java 后端绕不开持久层选型:以 MyBatis 为代表的"半自动 SQL 派",和以 JPA/Hibernate 为代表的"全自动 ORM 派"。它们不是谁淘汰谁,而是 SQL 控制力与开发效率的不同取舍。本节先对比,再给选型建议。
各自的设计哲学
- MyBatis:SQL 是中心。SQL 由你写(XML/注解),框架只做"参数进、结果出"的映射,resultMap 控制一切,数据库特性随手可用。
- JPA/Hibernate:实体是中心。你操作对象,框架按映射自动生成 SQL、管理表结构、脏检查与缓存,方言差异由框架屏蔽。
- Spring Data JPA:在 JPA 之上再封装仓库接口,方法名即可声明查询(以官方文档为准)。
关键维度对比
| 维度 | MyBatis | JPA/Hibernate |
|---|---|---|
| SQL 控制力 | 完全掌控 | 框架生成,优化靠 @Query/原生 SQL |
| 上手成本 | 会 SQL 就会用 | 概念多:实体状态、级联、懒加载 |
| 复杂动态查询 | XML 动态 SQL 灵活 | Criteria/Specification 较绕 |
| 单表 CRUD | 自己写或靠 MyBatis-Plus | 开箱即用 |
| 缓存 | 手动开二级缓存 | 一级会话缓存 + 成熟二级缓存 |
| 多表关联 | join 自己写、过程透明 | 映射自动管理,也易出 N+1 |
| 换数据库 | SQL 可能重写 | 方言自动适配,迁移友好 |
| 性能排查 | SQL 所见即所得 | 需先还原生成 SQL 再分析 |
典型踩坑对照
- JPA 的 N+1:关联默认懒加载,遍历集合逐个触发查询,要用 join fetch / @EntityGraph 预热(以官方文档为准)。
- MyBatis 的漏条件:动态 SQL 全手写,
<where>忘包就语法错误或全表扫描。 - JPA 状态管理:游离实体更新、脏检查有时"悄悄改库",调试成本高。
- MyBatis 映射事故:驼峰映射、null 值 jdbcType、一对多分页等坑,见本教程前面章节。
选型建议
| 团队/项目画像 | 推荐 |
|---|---|
| 报表、复杂查询、SQL 文化浓、老库约束多 | MyBatis(+ MyBatis-Plus 补 CRUD 效率) |
| 领域建模、CRUD 为主、需多数据库发行版 | JPA / Spring Data JPA |
| 混合 | 尽量统一一门,避免两套心智负担 |
一点提醒:两派都只是"把行变成对象"的路径,业务复杂度才是选型根本。单表 CRUD 多、对象模型清晰,选 JPA 省心;SQL 复杂、需要与 DBA 紧密协同审阅 SQL,MyBatis 系常占上风(经验性结论仅供参考,请结合团队实际)。
MyBatis 与 JPA 之争本质是"SQL 主权"之争:要全自动省心且对象模型清晰选 JPA;要 SQL 透明可控、与 DBA 高效协同选 MyBatis。具体能力边界以各自官方文档为准。