MyBatis 动态 SQL 笔记

动态 SQL 是 MyBatis 核心特性之一,支持根据不同条件动态拼接 SQL 语句,灵活适配复杂业务场景。

一、核心标签分类

标签类型 包含标签 作用
条件判断 <if><where><choose> 按条件动态拼接 SQL 片段
片段控制 <trim><set> 智能处理 SQL 片段的前缀、后缀(如 WHERESET 关键字)
循环遍历 <foreach> 遍历集合 / 数组,动态生成批量操作 SQL
片段复用 <sql><include> 抽取可复用的 SQL 片段,提升代码复用性

二、条件判断标签

1. <if> + <where>

作用:根据条件动态拼接 WHERE 子句,自动处理 AND/OR 关键字冗余问题。

示例

1
2
3
4
5
6
7
8
9
10
11
<select id="selectEmployeeByCondition" resultType="employee">
select emp_id,emp_name,emp_salary from t_emp
<where>
<if test="empName != null">
emp_name=#{empName}
</if>
<if test="empSalary != null">
and emp_salary>#{empSalary}
</if>
</where>
</select>
  • 若 empName 和 empSalary 都不为空,生成 WHERE emp_name=? AND emp_salary>?
  • 若某条件不满足,<where> 会自动剔除多余的 AND/OR

2. <choose> + <when> + <otherwise>

作用:多条件分支,仅执行第一个满足条件的分支(类似 Java if-else if-else)。

示例

1
2
3
4
5
6
7
8
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id,emp_name,emp_salary from t_emp where
<choose>
<when test="empName != null">emp_name=#{empName}</when>
<when test="empSalary &lt; 3000">emp_salary &lt; 3000</when>
<otherwise>1=1</otherwise>
</choose>
</select>
  • 若 empName 不为空,执行 emp_name=?
  • 若 empName 为空但 empSalary < 3000,执行 emp_salary < 3000
  • 若都不满足,执行 1=1(查询所有)。

三、片段控制标签

1. <trim>

作用:通过自定义前缀、后缀和覆盖规则,灵活控制 SQL 片段的拼接(可替代 <where><set>)。

属性说明

  • prefix:为 SQL 片段添加前缀(如 WHERE)。
  • suffix:为 SQL 片段添加后缀。
  • prefixOverrides:覆盖前缀的冗余关键字(如 ANDOR)。
  • suffixOverrides:覆盖后缀的冗余关键字(如 ,)。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<select id="selectEmployeeByConditionByTrim" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
<trim prefix="where" suffixOverrides="and|or">
<if test="empName != null">
emp_name=#{empName} and
</if>
<if test="empSalary &gt; 3000">
emp_salary>#{empSalary} and
</if>
<if test="empAge &lt;= 20">
emp_age=#{empAge} or
</if>
<if test="empGender=='male'">
emp_gender=#{empGender}
</if>
</trim>
</select>

2. <set>

作用:专用于 UPDATE 语句,自动处理 SET 子句中冗余的 ,

示例

1
2
3
4
5
6
7
8
9
10
11
12
<update id="updateEmployeeDynamic">
update t_emp
<set>
<if test="empName != null">
emp_name=#{empName},
</if>
<if test="empSalary &lt; 3000">
emp_salary=#{empSalary},
</if>
</set>
where emp_id=#{empId}
</update>

四、循环遍历标签 <foreach>

作用:遍历集合 / 数组,动态生成批量操作 SQL(如批量插入、批量查询 IN 条件)。

属性说明

  • collection:要遍历的集合 / 数组(必填)。
  • item:遍历过程中每个元素的别名(必填)。
  • separator:元素之间的分隔符(如 ,;)。
  • open:SQL 片段的前缀(如 values()。
  • close:SQL 片段的后缀(如 ))。
  • index:遍历 List 时为索引,遍历 Map 时为

示例 1:批量插入

1
2
3
<foreach collection="empList" item="emp" separator="," open="values" index="myIndex">
(#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
</foreach>

生成 SQL:values (?,0,?,?), (?,1,?,?)

示例 2:批量更新(需开启 allowMultiQueries=true

1
2
3
4
5
<update id="updateEmployeeBatch">
<foreach collection="empList" item="emp" separator=";">
update t_emp set emp_name=#{emp.empName} where emp_id=#{emp.empId}
</foreach>
</update>

生成 SQL:update ... where ...; update ... where ...

五、SQL 片段复用 <sql> + <include>

作用:抽取可复用的 SQL 片段(如列名、条件),通过 <include> 引用,提升代码复用性。

示例

1
2
3
4
5
6
7
8
9
10
11
<!-- 抽取可复用的列名片段 -->
<sql id="empColumn">
emp_id,emp_name,emp_age,emp_salary,emp_gender
</sql>

<!-- 引用片段 -->
<select id="getEmp" resultType="com.atguigu.mybatis.entity.Employee">
select
<include refid="empColumn"/>
from `t_emp` where id = #{id}
</select>

六、特殊字符转义

在 XML 中,以下特殊字符需使用转义字符,否则会导致解析错误:

原始字符 转义字符
& &amp;
< &lt;
> &gt;
" &quot;
' &apos;

示例empSalary &lt; 3000 表示 empSalary < 3000

七、动态 SQL 优势

  • 灵活性:根据业务条件动态生成 SQL,适配复杂查询场景。
  • 简洁性:通过标签自动处理 SQL 冗余(如多余的 ANDSET 后的 ,)。
  • 复用性:通过 <sql> 抽取片段,减少重复代码。