"小崔,注解不是来取代XML 的,是来解放你的。简单CRUD 写注解,复杂映射留XML,这叫各得其所。"——白歌
本章定位
一句话:本章解决"如何不用XML、直接在Java 接口上通过注解完成SQL 映射,以及注解与XML 如何取舍"的问题。
飞翔科技的微服务拆分后,小崔发现很多服务只有简单的单表CRUD,却还要维护一堆XML 文件。白歌提议:新服务的简单Mapper 全部用注解,老服务的复杂关联查询保留XML。这一章,小崔把MyBatis 的注解全家桶学透,并建立"注解 vs XML"的决策框架。
学习路线图
学习顺序说明:
- 先学四大CRUD 注解(@Select / @Insert / @Update / @Delete)→ 注解的"Hello World"
- 再学结果映射注解(@Results / @Result / @One / @Many)→ 注解版的resultMap 和association/collection
- 再学辅助注解(@Param / @Options / @SelectKey)→ 参数命名、选项配置、主键回写
- 最后看动态SQL 注解(@SelectProvider)→ 注解场景下的动态SQL 解决方案
文件关系说明
| 文件 | 一句话角色 |
|---|---|
Select.md | 查询注解:@Select 替代<select>,直接在接口方法上写SQL |
Insert.md | 插入注解:@Insert 替代<insert>,配合@Options 或@SelectKey 获取自增ID |
Update.md | 更新注解:@Update 替代<update>,适合单表全量/增量更新 |
Delete.md | 删除注解:@Delete 替代<delete>,简单删除的标准写法 |
Results.md | 结果映射容器:@Results 替代<resultMap>,内部嵌套多个@Result |
Result.md | 单列映射项:@Result 替代<id>/<result>,声明列与属性的对应关系 |
One.md | 一对一注解:@One 替代<association>,指定嵌套查询或嵌套结果 |
Many.md | 一对多注解:@Many 替代<collection>,指定嵌套查询或嵌套结果 |
Param.md | 参数命名注解:@Param 替代XML 中的参数名推断,多参数场景必备 |
Options.md | 选项配置注解:@Options 替代<insert>的属性(useGeneratedKeys、timeout 等) |
SelectKey.md | 主键回写注解:@SelectKey 替代<selectKey>,插入前/后查询主键 |
SelectProvider.md | 动态SQL 注解:@SelectProvider 等Provider 系列,通过Java 类动态生成SQL |
知识图谱
XML 标签 ↔ 注解对照表:
| XML 标签 | 注解 | 适用场景 |
|---|---|---|
<select> | @Select | 简单查询,SQL 短且固定 |
<insert> | @Insert | 单表插入,配合@Options 获取自增ID |
<update> | @Update | 单表更新,字段少、条件简单 |
<delete> | @Delete | 单条/批量删除 |
<resultMap> | @Results + @Result | 列名与属性名不一致,但嵌套不深 |
<association> | @One | 一对一关联,SQL 简单 |
<collection> | @Many | 一对多关联,数据量小 |
<selectKey> | @SelectKey | 非自增主键(如UUID、序列)回写 |
<sql> | 无直接等价 | 注解不支持SQL 片段复用,复杂复用场景回XML |
<if>/<where> | @SelectProvider | 动态SQL,通过Provider 类用Java 代码拼接 |
什么时候用XML,什么时候用注解?
| 场景 | 推荐方式 | 理由 |
|---|---|---|
| 简单单表CRUD | 注解 | 代码内聚,减少文件数量,维护成本低 |
| 复杂动态SQL(多条件) | XML | <if>/<where>/<foreach> 比Provider 类可读性高 |
| 复杂resultMap(多层嵌套) | XML | XML 的层级结构比@Results嵌套更清晰 |
| SQL 片段复用 | XML | <sql>标签支持全局复用,注解无此机制 |
| 需要DBA 审核SQL | XML | SQL 集中管理,便于版本控制和审计 |
| 快速原型/微服务 | 注解 | 开发速度快,适合简单服务的快速迭代 |
与下一章的衔接
本章学完后,小崔能用注解快速开发简单Mapper,但生产环境用户量一上来,同样的查询每秒执行几百次,数据库压力剧增。李眉的监控告警开始响。
下一章《缓存与性能优化》将解决:MyBatis 的一级缓存(SqlSession 级)和二级缓存(Mapper 级)如何工作、怎么配置、什么时候该用自定义缓存(Redis/Ehcache),以及分页插件和Executor 执行器的选择策略。
"注解让你写得快,缓存让你跑得快。两个快加起来,才是能上线的代码。"——大翔