mybatis
参考文档:The MyBatis Blog
帮助:MyBatis中文网
MyBatis 是什么
MyBatis 是一个半自动 ORM 框架。它不会像 JPA 那样把所有 SQL 都隐藏起来,而是让开发者自己编写 SQL,并负责把 SQL 参数和查询结果映射到 Java 对象。
如果要从零系统学习,先看这一页建立整体认识,再进入 MyBatis 核心全过程原理。核心页会把 Mapper 代理、SqlSession、Executor、BoundSql、参数绑定、结果映射、缓存、插件、事务和排查流程完整串起来。
它适合这些场景:
- 业务 SQL 比较复杂,需要开发者掌控执行细节。
- 团队希望 SQL 可见、可调优、可通过
explain分析。 - 项目以关系型数据库为主,需要灵活处理多表查询。
执行流程
mermaid
flowchart TD
A[Mapper 接口方法] --> B[SqlSession 代理调用]
B --> C[读取 MappedStatement]
C --> D[解析动态 SQL 和参数]
D --> E[创建 PreparedStatement]
E --> F[执行数据库 SQL]
F --> G[ResultSet 结果集]
G --> H[ResultMap 映射成对象]
H --> I[返回业务代码]核心组件
| 组件 | 作用 |
|---|---|
SqlSessionFactory | 创建 SqlSession 的工厂 |
SqlSession | 执行 SQL、提交事务、获取 Mapper |
Mapper | DAO 接口,业务代码主要调用它 |
MappedStatement | 一条 SQL 的完整描述,包括 SQL、参数、返回类型 |
Executor | 真正负责执行 SQL 的组件 |
TypeHandler | Java 类型和 JDBC 类型之间的转换 |
ResultMap | 查询结果和 Java 对象字段的映射关系 |
XML 和注解如何选择
| 方式 | 优点 | 缺点 |
|---|---|---|
| XML | 适合复杂 SQL,结构清晰,便于维护动态 SQL | 文件数量更多 |
| 注解 | 简单查询写起来快 | 复杂 SQL 可读性差 |
实践中建议:
- 简单单表查询可以用注解或 MyBatis-Plus。
- 复杂查询、动态条件、多表关联优先使用 XML。
- 核心 SQL 保持可读,避免把大量业务判断塞进 XML。
常见能力
- 动态 SQL:
if、choose、foreach、trim。 - 结果映射:一对一、一对多、字段别名映射。
- 缓存:一级缓存默认存在,二级缓存需要谨慎开启。
- 插件:分页、审计、SQL 改写、性能分析。
- 类型处理器:处理枚举、JSON、加密字段等特殊类型。
使用建议
- Mapper 方法命名要表达业务语义,不要只叫
queryList。 - 更新和删除必须带明确条件,必要时加防全表更新插件。
- 分页查询要关注总数 SQL 的性能。
- 批量写入要控制批次大小,避免单次 SQL 过大。
- 复杂 SQL 上线前用
explain检查索引和扫描行数。
深入学习路线
| 学习顺序 | 内容 | 目标 |
|---|---|---|
| 1 | MyBatis 核心全过程原理 | 理解 Mapper 方法到数据库返回对象的完整链路 |
| 2 | MyBatis 动态 SQL | 学会根据条件生成安全、可维护的 SQL |
| 3 | MyBatis 缓存机制 | 理解一级缓存、二级缓存和一致性风险 |
| 4 | MyBatis 拦截器 | 理解分页、审计、数据权限等扩展点 |
| 5 | MyBatis 批量操作 | 学会批量写入的性能边界和生产风险 |
| 6 | ORM 事务与一致性 | 理解事务边界为什么应该放在 Service 层 |
代码 Demo:Mapper 接口和 XML
Mapper 接口:
java
public interface UserMapper {
UserDO selectById(Long id);
List<UserDO> selectByStatus(Integer status);
}XML:
xml
<mapper namespace="com.example.UserMapper">
<resultMap id="UserMap" type="com.example.UserDO">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="status" property="status"/>
</resultMap>
<select id="selectById" resultMap="UserMap">
select id, username, status
from users
where id = #{id}
</select>
<select id="selectByStatus" resultMap="UserMap">
select id, username, status
from users
where status = #{status}
order by id desc
</select>
</mapper>重点:#{} 是预编译参数占位,能降低 SQL 注入风险;不要用字符串拼接用户输入。
为什么 MyBatis 适合 SQL 可控场景
MyBatis 的核心价值是让开发者显式控制 SQL,同时帮你完成参数绑定和结果映射。如果业务 SQL 很复杂,例如多表 join、报表查询、复杂动态条件,MyBatis 通常比全自动 ORM 更直观。
mermaid
flowchart TD
A["Mapper 方法"] --> B["XML / 注解 SQL"]
B --> C["参数绑定"]
C --> D["JDBC 执行"]
D --> E["ResultMap 映射对象"]如果不用 #{} 而是拼接字符串,用户输入可能改变 SQL 结构,产生 SQL 注入风险。MyBatis 的底线是:业务可以灵活写 SQL,但参数必须安全绑定。
