乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • XML 基础语法

    • XML 概述
    • XML 文档结构
    • XML 元素
    • XML 属性
    • XML 语法规则
    • XML 命名空间
    • XML 注释与处理指令
  • DTD 与文档验证

    • DTD 概述
    • DTD 元素声明
    • DTD 属性声明
    • DTD 实体声明
    • DTD 元素与属性对比
    • DTD 完整示例
  • XML Schema 定义

    • XML Schema 概述
    • XSD 简单类型
    • XSD 复杂类型
    • XSD 命名空间与引用
  • XPath 节点定位

    • XPath 概述
    • XPath 路径表达式
    • XPath 谓词与函数
  • XSLT 转换

    • XSLT 概述
    • XSLT 模板与匹配
    • XSLT 控制结构
    • XSLT 输出控制
  • XML 解析技术

    • XML 解析概述
    • DOM 解析
    • SAX 解析
    • StAX 解析
    • XML 与 Java — JAXP
  • XML 在 Java 中的应用

    • Spring XML 配置
    • MyBatis XML 映射
    • pom.xml 与 Maven
    • web.xml 配置详解
  • 现代数据格式对比

    • XML 与 JSON 对比
    • XML 与 YAML 对比
  • XML 显示与浏览器集成

    • XML 在浏览器中的显示
    • XMLHttpRequest 与 AJAX
    • 服务器端 XML 处理
  • XML 进阶查询与链接

    • XQuery 查询语言
    • XLink 超链接
    • XML 验证工具使用
  • XML Web 服务(选读)

    • XML Web 服务概述
    • SOAP 协议详解
    • WSDL 服务描述
    • RSS 内容聚合
    • RDF 资源描述框架

MyBatis XML 映射

本章定位 :掌握 MyBatis 的 XML Mapper 结构——resultMap、CRUD 标签、动态 SQL(if/choose/foreach)、#{} 与 ${} 的区别和安全性。

定义与作用

MyBatis 是 Java 中最流行的 ORM 半自动化框架。它的核心是 Mapper XML——将 SQL 语句与 Java 接口方法绑定的 XML 配置文件。

与全自动 ORM(如 Hibernate)不同,MyBatis 要求你 手写 SQL ,但帮你处理了参数映射、结果映射、动态 SQL 拼接等繁琐工作。这种"半自动"方式让你对 SQL 有完全的控制权,同时避免了 JDBC 的手工 setParameter/getResultSet。

核心原理:MyBatis 执行流程

图解释 :MyBatis 的执行流程是:①根据接口方法名找到对应的 Mapper XML SQL 语句;②将方法参数替换到 #{} 占位符(生成 PreparedStatement);③执行 SQL;④根据 resultMap 将 ResultSet 映射为 Java 对象。

语法/结构要点

Mapper XML 骨架

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.feixiang.edu.mapper.StudentMapper">

  <!-- resultMap:自定义结果映射 -->
  <resultMap id="studentMap" type="Student">
    <id property="id" column="student_id"/>
    <result property="name" column="student_name"/>
    <result property="gpa" column="grade_point_avg"/>
  </resultMap>

  <!-- CRUD -->
  <select id="findById" resultMap="studentMap">
    SELECT * FROM student WHERE student_id = #{id}
  </select>

  <insert id="insert" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO student (student_name, grade_point_avg)
    VALUES (#{name}, #{gpa})
  </insert>

  <update id="update">
    UPDATE student SET student_name = #{name} WHERE student_id = #{id}
  </update>

  <delete id="delete">
    DELETE FROM student WHERE student_id = #{id}
  </delete>
</mapper>

动态 SQL 标签

标签作用示例
if条件判断<if test="name != null">AND name = #{name}</if>
choose/when/otherwise多路分支优先级排序
where智能添加/去除 WHERE自动处理前导 AND/OR
set智能添加 SET自动处理后缀逗号
foreach遍历集合IN (#{item}, #{item}, ...)
trim自定义前缀/后缀/覆盖更灵活的 where/set

完整示例:小崔用动态 SQL 写教学管理查询

场景说明

飞翔科技的后端 小崔 要实现学生搜索功能——支持按姓名、专业、GPA 范围组合查询,条件全部可选。如果用拼接字符串的方式,需要几十行的 if-else,他用 MyBatis 动态 SQL 优雅解决。

Mapper XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.feixiang.edu.mapper.StudentMapper">

  <resultMap id="studentMap" type="com.feixiang.edu.domain.Student">
    <id property="id" column="student_id"/>
    <result property="name" column="student_name"/>
    <result property="major" column="major"/>
    <result property="gpa" column="grade_point_avg"/>
    <result property="enrollYear" column="enroll_year"/>
  </resultMap>

  <!-- 基础查询:按 ID -->
  <select id="findById" resultMap="studentMap">
    SELECT student_id, student_name, major, grade_point_avg, enroll_year
    FROM student
    WHERE student_id = #{id}
  </select>

  <!-- 动态条件搜索 -->
  <select id="search" resultMap="studentMap">
    SELECT student_id, student_name, major, grade_point_avg, enroll_year
    FROM student
    <where>
      <if test="name != null and name != ''">
        AND student_name LIKE CONCAT('%', #{name}, '%')
      </if>
      <if test="major != null and major != ''">
        AND major = #{major}
      </if>
      <if test="minGpa != null">
        AND grade_point_avg &gt;= #{minGpa}
      </if>
      <if test="maxGpa != null">
        AND grade_point_avg &lt;= #{maxGpa}
      </if>
      <if test="enrollYear != null">
        AND enroll_year = #{enrollYear}
      </if>
    </where>
    <if test="orderBy != null">
      ORDER BY ${orderBy}
      <if test="desc">
        DESC
      </if>
    </if>
  </select>

  <!-- 批量删除:foreach -->
  <delete id="batchDelete">
    DELETE FROM student
    WHERE student_id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
      #{id}
    </foreach>
  </delete>

  <!-- 动态更新:set -->
  <update id="updateSelective">
    UPDATE student
    <set>
      <if test="name != null">student_name = #{name},</if>
      <if test="major != null">major = #{major},</if>
      <if test="gpa != null">grade_point_avg = #{gpa},</if>
    </set>
    WHERE student_id = #{id}
  </update>

  <!-- 多路排序 -->
  <select id="listByPriority" resultMap="studentMap">
    SELECT * FROM student
    <where>
      <choose>
        <when test="priority == 'high_gpa'">
          grade_point_avg &gt;= 3.5
        </when>
        <when test="priority == 'new_student'">
          enroll_year = #{currentYear}
        </when>
        <otherwise>
          1 = 1
        </otherwise>
      </choose>
    </where>
  </select>
</mapper>

Java 接口

public interface StudentMapper {
    Student findById(@Param("id") Long id);

    List<Student> search(
        @Param("name") String name,
        @Param("major") String major,
        @Param("minGpa") Double minGpa,
        @Param("maxGpa") Double maxGpa,
        @Param("enrollYear") Integer enrollYear,
        @Param("orderBy") String orderBy,
        @Param("desc") Boolean desc
    );

    int batchDelete(@Param("ids") List<Long> ids);
}

操作结果

// 搜索:CS 专业 + GPA ≥ 3.0
List<Student> result = mapper.search(
    null, "CS", 3.0, null, null, "grade_point_avg", true
);
// 生成 SQL:
// SELECT ... FROM student WHERE major = 'CS' AND grade_point_avg >= 3.0
// ORDER BY grade_point_avg DESC

// 只传姓名:模糊搜索
List<Student> result2 = mapper.search("小", null, null, null, null, null, null);
// 生成 SQL:
// SELECT ... FROM student WHERE student_name LIKE '%小%'

动态 SQL 自动处理了 WHERE 子句中的前导 AND——如果所有条件都不满足,<where> 完全消失,不会产生 WHERE 空子句。

易错场景

错误一:#{} 和 ${} 混淆

  • #{}:预编译占位符(PreparedStatement),安全,自动加引号
  • ${}:字符串替换(Statement),有 SQL 注入风险, 仅用于ORDER BY/表名/列名等动态标识符
<!-- ❌ 危险:${orderBy} 可能注入 DROP TABLE -->
SELECT * FROM student ORDER BY ${orderBy}

<!-- ⚠️ 必须用 ${} 时,在 Java 层做白名单校验 -->

错误二:<if test="name == '小崔'"> 中字符串比较

MyBatis 的 OGNL 表达式中,字符串比较必须用双引号包裹:

<!-- ❌ -->
<if test="major == 'CS'">

<!-- ✅ -->
<if test='major == "CS"'>

面试考点

考点参考答案要点
MyBatis 中 #{} 和 ${} 的区别?#{} 是预编译占位符(PreparedStatement),安全防注入;${} 是字符串直接替换,可能被注入,仅用于动态表名/列名/ORDER BY
resultMap 和 resultType 的区别?resultType 自动映射(要求列名=属性名);resultMap 手动定义列→属性的映射规则,处理复杂映射(关联/集合/继承)
MyBatis 动态 SQL 有哪些常用标签?if(条件判断)、choose/when/otherwise(多路分支)、where(智能 WHERE)、set(智能 SET)、foreach(遍历集合)、trim(自定义裁剪)
上一页
Spring XML 配置
下一页
pom.xml 与 Maven