MyBatis 是半自动 ORM 框架,由开发者手写 SQL,框架仅负责安全传参和结果映射;其优势在于 SQL 完全可控、支持数据库特有语法与复杂查询,适用于高优化 SQL、千万级分页及混合数据源场景,但需承担移植性差、维护成本高等代价。

MyBatis 是一个你写 SQL、它帮你执行和映射的半自动 ORM 框架——不是它替你生成 SQL,而是你掌控 SQL,它只负责“安全地传参 + 准确地装箱”。
为什么说 MyBatis 是“半自动”?关键在 SQL 控制权
全自动框架(比如 Hibernate)根据对象关系自动生成 SELECT * FROM user WHERE id = ?;而 MyBatis 要求你亲手写出这句,甚至写成 SELECT id, name, email FROM user WHERE status = #{status} AND create_time > #{minTime}。这不是负担,是授权:
- 你可以用数据库特有语法:MySQL 的
ON DUPLICATE KEY UPDATE、Oracle 的ROWNUM、PostgreSQL 的jsonb_path_exists - 联表查询时,字段别名、嵌套对象组装、一对多结果聚合,全由你定义,不依赖框架猜意图
- 遇到慢查询,直接看执行计划——SQL 就是你写的,不用翻源码猜 Hibernate 生成了什么
坑点:有人误以为“写了 XML 就算半自动”,其实如果用 @Select("SELECT * FROM ...") 硬编码在接口里,就失去了 SQL 与代码分离的优势,等于退化回 JDBC。
什么时候必须选 MyBatis?看这三类业务场景
不是所有项目都适合抽象掉 SQL,以下场景中,MyBatis 的优势会直接变成上线节奏或性能底线:
-
已有高优化 SQL 或存储过程:金融/政务系统常要求所有业务逻辑走 DB 层存储过程,MyBatis 可直调
{call proc_user_report(?, ?)},Hibernate 很难干净接入 -
千万级单表分页 or 多维条件筛查:比如“查近 30 天活跃用户,排除黑名单,按设备类型聚合,再按地域 TOP10 排序”,这种 SQL 需要手调索引提示、避免
OFFSET深翻,MyBatis 允许你写SELECT /*+ USE_INDEX(user idx_status_time) */ ... -
混合数据源读取:主库查用户,ES 查日志,Redis 查缓存状态——MyBatis 的
Mapper只管数据库这一环,不绑架你整个数据访问链路
反例:若项目 90% 是增删改查标准单表操作,且团队缺乏 SQL 能力,硬上 MyBatis 会拖慢开发,这时 MyBatis-Plus 的 QueryWrapper 才是更务实的选择。
性能与灵活性的真实代价:数据库移植性弱、SQL 维护成本高
MyBatis 快,是因为它不做运行时 SQL 解析、不代理对象、不拦截方法调用——但代价也很实在:
- 换数据库 ≠ 改个
driver-class-name:MySQL 的IFNULL得换成 Oracle 的NVL,分页写法从LIMIT ?,?切到ROWNUM或OFFSET/FETCH,这些都得手动改xxxMapper.xml - 动态 SQL 写错不报编译错误:比如
<if test="id != null">AND id = #{id}</if>中的test表达式写成id != '',运行时才空指针——建议单元测试覆盖所有参数组合分支 - 过度使用
<foreach>拼 IN 列表:传入 5000 个 ID 会触发 MySQL 的max_allowed_packet限制,应拆批或改用临时表
真正容易被忽略的是:MyBatis 的“轻量”不等于“零配置”。一旦开启二级缓存、插件(如分页插件 PageHelper)、多数据源路由,它的行为边界就开始模糊——此时出问题,往往不是 SQL 写错了,而是 SqlSessionFactory 的生命周期或事务传播配置没对齐 Spring。










