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 注入"),欢迎继续提问,我可以给出更具体的代码示例。

相关推荐
ruleslol9 小时前
SpringBoot13-小细节
spring boot·mybatis
程序员三明治14 小时前
【MyBatis从入门到入土】告别JDBC原始时代:零基础MyBatis极速上手指南
数据库·mysql·mybatis·jdbc·数据持久化·数据
Mr_Chester15 小时前
mybatis OGNL+优雅处理简单逻辑
java·tomcat·mybatis
涵涵(互关)1 天前
Maven多模块项目MyMetaObjectHandler自动填充日期未生效
spring·maven·mybatis
ss2731 天前
手写MyBatis第96弹:异常断点精准捕获MyBatis深层BUG
java·开发语言·bug·mybatis
lang201509281 天前
MyBatis配置全解析:核心要点详解
mybatis
yunmi_2 天前
安全框架 SpringSecurity 入门(超详细,IDEA2024)
java·spring boot·spring·junit·maven·mybatis·spring security
wuxuanok2 天前
苍穹外卖 —— 公共字段填充
java·开发语言·spring boot·spring·mybatis
伯明翰java2 天前
mybatis-generator插件自动生成mapper及其实体模型配置
java·开发语言·mybatis