简介
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示:你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。
当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
<foreach>
标签是 MyBatis 中非常重要且强大的标签之一,主要用于生成循环语句,并根据集合元素动态生成 SQL。它是实现动态 SQL 的核心之一,尤其在处理批量插入、批量更新、批量删除等操作时非常有用。
作用
<foreach>
标签的主要作用是遍历集合,动态生成 SQL 中的一部分(如 IN
子句、VALUES
子句等),并且可以控制元素的分隔符、开始和结束符号。
语法
<foreach
collection="集合对象"
item="集合元素的名称"
index="集合元素的索引(可选)"
open="开始符号(可选)"
close="结束符号(可选)"
separator="分隔符(可选)">
循环体内容
</foreach>
参数
collection
:指定要遍历的集合对象,通常是List
、Set
、Array
或Map
。item
:指定集合中每个元素的名称,遍历过程中,可以在 SQL 中使用这个名称来引用当前元素。index
:可选,指定集合中每个元素的索引,通常在遍历过程中不常用,但如果需要索引值可以启用。open
:可选,指定循环体开始部分的符号或字符(通常用于在IN
子句中添加括号等符号)。close
:可选,指定循环体结束部分的符号或字符(通常用于在IN
子句中闭合括号等)。separator
:可选,指定循环体元素之间的分隔符(例如:在生成IN
子句时使用逗号,
分隔元素)。
例子
1. 生成 IN
子句
当需要使用 IN
子句进行查询(例如,批量查询),可以利用 <foreach>
标签生成动态的 SQL 语句。
<select id="selectUsersByIds" resultType="User">
SELECT id, username, email
FROM t_user
WHERE id IN
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
</select>
解释:
collection="userIds"
:遍历userIds
集合。item="userId"
:每次遍历时,将userId
作为当前元素传递给 SQL。open="(" close=")"
:在IN
子句两边加上括号。separator=","
:元素之间用逗号分隔。
假设 userIds
集合为 [1, 2, 3]
,生成的 SQL 为:
SELECT id, username, email FROM t_user WHERE id IN (1, 2, 3);
2. 批量插入
通过 <foreach>
标签,可以非常方便地实现批量插入的功能。
<insert id="insertUsers">
INSERT INTO t_user (username, email, password)
VALUES
<foreach collection="users" item="user" separator=",">
(#{user.username}, #{user.email}, #{user.password})
</foreach>
</insert>
解释:
collection="users"
:遍历传入的users
集合。item="user"
:每次遍历时,将集合中的每个user
对象传递给 SQL。separator=","
:每一组插入值之间使用逗号分隔。- 在
VALUES
部分,每个user
对象对应一个(#{user.username}, #{user.email}, #{user.password})
插入值。
假设 users
集合中有三个用户,生成的 SQL 为:
INSERT INTO t_user (username, email, password)
VALUES
('user1', 'user1@example.com', 'password1'),
('user2', 'user2@example.com', 'password2'),
('user3', 'user3@example.com', 'password3');
3. 批量更新
批量更新时,可以结合 <foreach>
标签动态生成更新的 SQL 语句。
<update id="updateUsers">
<foreach collection="users" item="user" separator=";">
UPDATE t_user
SET email = #{user.email}, password = #{user.password}
WHERE id = #{user.id}
</foreach>
</update>
解释:
collection="users"
:遍历users
集合,针对每个用户生成更新语句。separator=";"
:每条更新语句之间使用分号分隔。
假设 users
集合中有三个用户,生成的 SQL 为:
UPDATE t_user SET email = 'user1@example.com', password = 'password1' WHERE id = 1;
UPDATE t_user SET email = 'user2@example.com', password = 'password2' WHERE id = 2;
UPDATE t_user SET email = 'user3@example.com', password = 'password3' WHERE id = 3;
4. 条件动态构建 SQL
你还可以在 WHERE
子句中使用 <foreach>
来动态构建复杂的查询条件。例如:
<select id="selectUsersByConditions" resultType="User">
SELECT id, username, email
FROM t_user
WHERE 1 = 1
<foreach collection="userIds" item="userId" open="AND (" close=")" separator="OR">
id = #{userId}
</foreach>
</select>
解释:
collection="userIds"
:遍历userIds
集合,生成多个OR
条件。open="AND (" close=")"
:将这些条件放在AND
之后,并且包裹在括号中。separator="OR"
:每个条件之间用OR
连接。
假设 userIds
为 [1, 2, 3]
,生成的 SQL 为:
SELECT id, username, email FROM t_user WHERE 1 = 1 AND (id = 1 OR id = 2 OR id = 3);
总结
<foreach>
标签用于动态生成 SQL 语句中的多个相似部分,特别适用于批量操作。- 常见的应用场景包括批量查询(
IN
)、批量插入、批量更新等。 - 通过
open
、close
和separator
可以控制生成的 SQL 语句的格式和结构,提供了极大的灵活性。 - 使用
<foreach>
标签时,一定要小心确保参数安全性,避免 SQL 注入问题(尤其是拼接字符串时)。