MyBatis 动态 SQL 核心标签教程:_if_, _where_, _foreach_
一、动态 SQL 简介
MyBatis 动态 SQL 允许根据条件动态拼接 SQL 语句,避免手动处理字符串拼接的复杂性和 SQL 注入风险。核心标签包括 <if>
、<where>
、<foreach>
等。以下通过示例详细讲解其用法。
二、<if>
** 标签**
用途:根据条件动态插入 SQL 片段。
属性:
test
:必填,条件表达式(基于 OGNL 语法)。
示例 1:根据 id 和 name 查询员工
<select id="findByIdAndName" resultType="cn.cjxy.domain.Emp">SELECT * FROM EMP<where><if test="id != null">AND id = #{id} <!-- 当 id 不为空时拼接 --></if><if test="name != null">AND name = #{name} <!-- 当 name 不为空时拼接 --></if></where>
</select>
注意:
<if>
通常与<where>
配合使用,避免单独处理WHERE
和AND
的冗余问题。- 如果所有条件均不满足,
<where>
会忽略整个WHERE
子句。
三、<where>
** 标签**
用途:智能处理 WHERE
子句,自动删除多余的 AND
或 OR
。
特性:
- 如果
<where>
内无有效条件,不会生成WHERE
关键字。 - 自动去除子句中开头的
AND
或OR
。
示例 2:多条件查询
<select id="findByCondition" resultType="Emp">SELECT * FROM EMP<where><if test="dept != null">AND dept = #{dept} <!-- 自动处理开头的 AND --></if><if test="salary > 5000">OR salary > #{salary}</if></where>
</select>
输出 SQL:
- 当
dept
非空且salary > 5000
时:
SELECT * FROM EMP WHERE dept = ? OR salary > ?
- 当所有条件为空时:
SELECT * FROM EMP
四、<foreach>
** 标签**
用途:遍历集合(如 List、数组、Map),生成动态 SQL(常用于 IN
查询)。
属性:
collection
:必填,传入的集合参数名。item
:必填,遍历时的元素别名。open
:可选,循环开始时的字符串(如(
)。separator
:必填,元素间的分隔符(如,
)。close
:可选,循环结束时的字符串(如)
)。
示例 3:根据多个 id 查询员工
<select id="findByIds" resultType="Emp">SELECT * FROM emp<where>id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id} <!-- 遍历集合生成 id1, id2, ... --></foreach></where>
</select>
参数传递:
- 如果参数是
List
或数组,collection
需指定为list
或array
。 - 如果参数是对象中的属性,需通过
paramName.ids
指定。
示例 4:批量插入员工
<insert id="batchInsert">INSERT INTO emp (name, dept) VALUES<foreach collection="empList" item="emp" separator=",">(#{emp.name}, #{emp.dept}) <!-- 遍历生成多组值 --></foreach>
</insert>
生成 SQL:
INSERT INTO emp (name, dept) VALUES (?, ?), (?, ?), (?, ?)
五、组合使用示例
场景:根据姓名模糊查询 + 部门筛选 + 多 id 过滤。
<select id="complexQuery" resultType="Emp">SELECT * FROM emp<where><if test="name != null">name LIKE CONCAT('%', #{name}, '%') <!-- 模糊查询 --></if><if test="dept != null">AND dept = #{dept}</if><if test="ids != null and !ids.isEmpty()">AND id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></if></where>
</select>
六、常见问题
<if>
** 中条件表达式错误**- 错误:
test="id == null"
(应使用=
而非==
)。 - 正确:
test="id = null"
或test="id eq null"
。
- 错误:
<foreach>
** 的collection
参数类型不匹配**- 若参数是
List
,需指定collection="list"
;若为Map
中的键,则用collection="keyName"
。
- 若参数是
<where>
** 未正确处理动态条件**- 确保所有条件中的
AND
/OR
写在条件内部,如<if test="..."> AND ... </if>
。
- 确保所有条件中的
七、总结
<if>
:按需拼接条件,避免冗余代码。<where>
:智能处理WHERE
子句,解决开头AND
问题。<foreach>
:遍历集合生成动态 SQL,简化批量操作。
通过灵活组合这些标签,可以轻松实现复杂查询逻辑,同时保持代码简洁性和可维护性。