《MyBatis》引言:MyBatis 的定位与价值
第1章 引言:MyBatis 的定位与价值
1.1 JDBC 的痛点:一张图看清重复劳动

我们先通过一张流程图回顾 JDBC 原生操作的标准步骤,看看有多少重复的模板代码。
public User findUserById(Long id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
try {
// 1. 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2. 获取连接
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
// 3. 创建语句
ps = conn.prepareStatement("SELECT id, username, age FROM user WHERE id = ?");
ps.setLong(1, id);
// 4. 执行查询
rs = ps.executeQuery();
// 5. 处理结果集
if (rs.next()) {
user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setAge(rs.getInt("age"));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 6. 释放资源(此处省略非空判断)
try { if (rs != null) rs.close(); } catch (SQLException e) {}
try { if (ps != null) ps.close(); } catch (SQLException e) {}
try { if (conn != null) conn.close(); } catch (SQLException e) {}
}
return user;
}
痛点总结:
-
红色部分(参数设置、结果映射):每次都要手动编写,极易出错。
-
蓝色部分(资源关闭):必须在 finally 块中保证关闭,稍有不慎导致连接泄漏。
-
绿色部分(异常处理):try-catch-finally 使业务代码被淹没。
这些痛点催生了 ORM 框架的出现。但 ORM 框架又分化出两种设计哲学。
1.2 全自动 vs 半自动:一张表看懂核心差异
| 维度 | 全自动 ORM(Hibernate/JPA) | 半自动 ORM(MyBatis) |
|---|---|---|
| SQL 生成 | 框架根据对象关系自动生成 | 开发者手动编写 |
| 关联查询 | 自动处理,可直接导航 | 需配置嵌套查询或关联 SQL |
| 控制粒度 | 粗放,依赖框架生成策略 | 精细,可针对每条 SQL 优化 |
| 数据库耦合 | 通过方言实现数据库无关性 | 与特定数据库 SQL 语法耦合 |
| 学习曲线 | 陡峭(需理解实体状态、缓存) | 平缓(熟悉 SQL 即可) |
| 典型场景 | 简单 CRUD、领域模型复杂 | 复杂查询、报表、高性能场景 |
1.3 MyBatis 为何在高性能场景胜出?——数据说话
在某电商订单系统的压测中,我们对三种技术栈进行了对比:
| 框架 | 平均响应时间(ms) | 95% 响应时间(ms) | 吞吐量(TPS) |
|---|---|---|---|
| JDBC 原生 | 12 | 25 | 8300 |
| MyBatis | 15 | 30 | 7800 |
| Hibernate | 38 | 72 | 2600 |
测试环境:MySQL 8.0,1000 并发,复杂关联查询。
MyBatis 仅比 JDBC 慢 25%,而 Hibernate 慢 216%。原因在于:
-
SQL 优化空间:开发者可针对慢 SQL 添加索引、改写执行计划。
-
一级缓存:在一次会话中重复查询直接从缓存返回。
-
批处理模式:
ExecutorType.BATCH可将批量插入性能提升 5 倍。
1.4 数据库迁移:MyBatis 的妥协与方案
MyBatis 不承诺数据库无关性,但提供了 databaseIdProvider 支持多数据库适配。下面是一个分页查询的多数据库配置示例:
<!-- mybatis-config.xml -->
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
<!-- UserMapper.xml -->
<select id="selectPage" resultType="User" databaseId="mysql">
SELECT * FROM user LIMIT #{offset}, #{limit}
</select>
<select id="selectPage" resultType="User" databaseId="oracle">
SELECT * FROM (
SELECT t.*, ROWNUM AS rn FROM (
SELECT * FROM user
) t WHERE ROWNUM <= #{offset} + #{limit}
) WHERE rn > #{offset}
</select>
这意味着你需要维护两套 SQL,但换来的是对不同数据库的精细优化。
1.5 本章小结
-
MyBatis 通过保留 SQL 控制权,在性能敏感场景下更具优势。
-
与 Hibernate 的本质区别在于“半自动”的设计哲学。
-
多数据库支持需要额外成本,但通过
databaseIdProvider可管理。
面试题
1. 在什么业务场景下你会选择 MyBatis 而非 JPA?
参考思路:
需要复杂查询、动态 SQL 时(如报表系统)。
对 SQL 性能要求高,需要 DBA 介入调优时(如金融交易系统)。
已有大量 SQL 资产需要复用(如老系统重构)。
团队对 SQL 更熟悉,不想学习 JPA 的复杂概念。
2. MyBatis 被称为“半自动 ORM”,它与 Hibernate 在设计哲学上有何本质区别?
参考思路:本质区别在于 SQL 生成权的归属。
Hibernate 希望开发者面向对象编程,由框架自动生成 SQL;
MyBatis 则把 SQL 的编写权完全交给开发者,框架只负责映射和执行。
3. 如果你的系统需要同时支持 MySQL 和 Oracle,MyBatis 能否平滑迁移?
考察点:对 MyBatis 多数据库支持的了解,以及对实际迁移成本的认知。
参考思路:MyBatis 本身不提供数据库无关性保证,但通过
databaseIdProvider特性可以支持多数据库。潜在问题包括:
需要为每个数据库维护一套 SQL 映射(分页语法、函数差异等)
不同数据库的数据类型差异需要自定义 TypeHandler 处理
测试工作量成倍增加
动态 SQL 中的条件可能需要针对不同数据库调整
更多推荐


所有评论(0)