MyBatis Mapper XML 核心详解

以下内容是关于 MyBatis 框架中 Mapper XML 文件 的官方文档或技术说明,内容非常全面。您问"怎么理解",我将为您系统地、通俗地解析这份文档的核心要点,帮助您掌握 MyBatis 的核心思想和关键组件。


一、核心思想:MyBatis 的设计哲学

"The true power of MyBatis is in the Mapped Statements."

(MyBatis 的真正力量在于"映射语句")

MyBatis 是一个 半自动化的 ORM(对象关系映射)框架,它不像 Hibernate 那样完全隐藏 SQL,而是:

  • 让你写 SQL
  • 帮你处理参数设置和结果映射
  • 极大减少 JDBC 冗余代码(文档说节省 95%)

它不试图"取代 SQL",而是"增强 SQL 的能力"。


二、Mapper XML 的核心元素(按推荐顺序)

元素 说明
<cache> 配置当前命名空间的二级缓存
<cache-ref> 引用其他命名空间的缓存配置
<resultMap> 最强大、最复杂的元素,定义数据库结果集如何映射到 Java 对象
<sql> 可重用的 SQL 片段
<insert> 插入语句
<update> 更新语句
<delete> 删除语句
<select> 查询语句

⚠️ 注意:<parameterMap>废弃,不再使用。


三、核心元素详解

1. <select> 查询语句

xml 复制代码
<select id="selectPerson" parameterType="int" resultType="hashmap">
  SELECT * FROM PERSON WHERE ID = #{id}
</select>
  • id:在当前命名空间内唯一标识这个 SQL。
  • parameterType:传入参数的类型(可选,MyBatis 能自动推断)。
  • resultType:返回结果的类型(如 UserHashMap 等)。
  • #{id}预编译参数 ,防止 SQL 注入,等价于 JDBC 的 ?
📌 重要属性
属性 说明
resultMap 引用外部 <resultMap>,用于复杂映射(和 resultType 二选一)
useCache 是否使用二级缓存(默认 true
flushCache 是否清空缓存(默认 false
timeout 查询超时时间(秒)
fetchSize 提示数据库每次返回多少行数据(优化大数据量查询)

2. <insert><update><delete>

xml 复制代码
<insert id="insertAuthor">
  INSERT INTO Author (username, password, email) 
  VALUES (#{username}, #{password}, #{email})
</insert>
🔑 特殊属性(仅 insert/update)
属性 说明
useGeneratedKeys="true" 使用数据库自增主键(如 MySQL)
keyProperty="id" 将生成的主键值赋给 Java 对象的 id 属性
keyColumn="ID" 指定数据库中生成主键的列名(PostgreSQL 等需要)
🌟 <selectKey>:手动生成主键(适用于不支持自增的数据库)
xml 复制代码
<insert id="insertAuthor">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    SELECT CAST(RANDOM()*1000000 AS INTEGER) FROM SYSIBM.SYSDUMMY1
  </selectKey>
  INSERT INTO Author (id, username) VALUES (#{id}, #{username})
</insert>
  • order="BEFORE":先生成主键再插入。
  • order="AFTER":先插入再查主键(如 Oracle 的 RETURNINGCURRVAL)。

3. <sql>:可重用 SQL 片段

xml 复制代码
<sql id="userColumns">
  ${alias}.id, ${alias}.username, ${alias}.password
</sql>

<select id="selectUsers" resultType="map">
  SELECT 
    <include refid="userColumns"><property name="alias" value="t1"/></include>,
    <include refid="userColumns"><property name="alias" value="t2"/></include>
  FROM users t1 CROSS JOIN users t2
</select>
  • <include> 引用 SQL 片段。
  • ${alias}字符串替换(注意 SQL 注入风险)。

4. 参数处理:#{} vs ${}

语法 说明 安全性 用途
#{param} 预编译参数 ,使用 ? 占位符 ✅ 安全 一般参数(如 WHERE id = #{id}
${param} 字符串替换,直接拼接 SQL ❌ 有 SQL 注入风险 动态表名、列名(如 ORDER BY ${column}

✅ 最佳实践:

  • 用户输入的列名/表名,必须做白名单校验。
  • 能用 #{} 就不用 ${}

5. <resultMap>:最强大的映射工具

场景:当数据库字段名 ≠ Java 属性名
xml 复制代码
<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id"/>
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

<select id="selectUsers" resultMap="userResultMap">
  SELECT user_id, user_name, hashed_password FROM users WHERE id = #{id}
</select>
  • <id>:映射主键,有助于性能优化。
  • <result>:普通字段映射。
高级用法:关联映射(一对一、一对多)
xml 复制代码
<resultMap id="detailedBlogResultMap" type="Blog">
  <id property="id" column="blog_id"/>
  <result property="title" column="blog_title"/>
  
  <!-- 一对一:博客属于一个作者 -->
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
  </association>

  <!-- 一对多:博客有多个文章 -->
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
  </collection>
</resultMap>
  • association:一对一关联(如 Blog → Author)
  • collection:一对多关联(如 Blog → List)
  • ofType:集合中元素的类型(相当于泛型)
🌟 <discriminator>:鉴别器(多态映射)
xml 复制代码
<discriminator javaType="int" column="draft">
  <case value="1" resultType="DraftPost"/>
  <case value="0" resultType="PublishedPost"/>
</discriminator>

根据 draft 字段的值,决定使用哪个 resultType,实现"一个查询返回不同子类"。


四、总结:如何理解这份文档?

维度 理解
定位 MyBatis 不是"全自动 ORM",而是"SQL 增强器"
核心 <select> + <resultMap> 解决了 JDBC 最繁琐的部分
优势 写 SQL 自由,映射灵活,性能可控
风险 使用 ${} 时需警惕 SQL 注入
最佳实践 从小 resultMap 开始,逐步构建复杂映射,配合单元测试

五、学习建议

  1. 先掌握简单映射resultType + 别名 + #{} 参数
  2. 再学 <resultMap>:处理字段名不一致
  3. 再学关联映射associationcollection
  4. 最后学高级特性<discriminator>、缓存、动态 SQL

如果您有具体的使用场景(比如"如何实现一对多查询"或"如何防止 SQL 注入"),欢迎继续提问,我可以给出更具体的代码示例。

相关推荐
Java&Develop15 小时前
使用 JDOM 库生成 XML 文件并返回 File
xml
W.Buffer18 小时前
MyBatis 源码深度解析:从 Spring Boot 实战到底层原理
spring boot·后端·mybatis
关关长语20 小时前
Dotnet使用System.Xml.Serialization处理Xml序列化
xml·c#·.net
Dolphin_Home20 小时前
轻量实用的 XML 与 JSON / 对象互转工具类(Jackson 实现)
xml·java·json
CS Beginner21 小时前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
huluang1 天前
XML文档差异分析工具:深入解析Word XML结构变化
xml·word
m0_564264182 天前
IDEA DEBUG调试时如何获取 MyBatis-Plus 动态拼接的 SQL?
java·数据库·spring boot·sql·mybatis·debug·mybatis-plus
未孤_有青山2 天前
库卡机器人通讯-EtherKRL-XML格式
xml·c#
没有bug.的程序员2 天前
Spring Boot 整合第三方组件:Redis、MyBatis、Kafka 实战
java·spring boot·redis·后端·spring·bean·mybatis
迷了璐的航2 天前
mybatis解决查询中使用group by时出现sql_mode=only_full_group_by
数据库·sql·mybatis