MyBatis的<foreach>标签需规范使用:collection属性须与@Param命名一致;空集合时用<if>配合1=2避免语法错误;IN元素超1000应分批查询;参数类型必须与数据库字段严格匹配,禁用'#{id}'防止SQL注入。

MyBatis 的 <foreach> 标签是处理集合参数、生成动态 SQL(尤其是 IN 查询)的核心工具。用得好,能避免 N+1 查询、减少数据库交互次数;用得不好,可能触发 SQL 注入、空集合报错或性能下降。关键在于写法规范、边界控制和类型适配。
明确 collection 属性来源:别写错参数名
MyBatis 会将传入的参数封装为一个 Map。当方法接收单个集合参数(如 List<Long> ids)时,collection 值默认为 "list";若参数被 @Param("ids") 显式命名,则 collection 必须写成 "ids"。常见错误是硬写 collection="list" 却用了 @Param,导致遍历失败。
建议统一使用 @Param 显式命名,提升可读性与健壮性:
public List<User> selectByIds(@Param("ids") List<Long> ids);对应 XML 中写法:
立即学习“Java免费学习笔记(深入)”;
<select id="selectByIds" resultType="User">
SELECT * FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>安全处理空集合:避免 SQL 语法错误
当传入空集合时,上述 SQL 会变成 WHERE id IN (),直接报错。需配合 <if> 判断兜底:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 返回空结果集:加条件拦截,让 SQL 不执行
- 改用
1=2等恒假条件,保持 SQL 合法
推荐写法:
<select id="selectByIds" resultType="User">
SELECT * FROM user
<where>
<if test="ids != null and !ids.isEmpty()">
id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
<if test="ids == null or ids.isEmpty()">
1 = 2
</if>
</where>
</select>优化 IN 元素数量:防止超长 SQL 或参数过多
MySQL 默认 max_allowed_packet 限制单条 SQL 长度,Oracle 对绑定变量数有限制(如 1000 个)。若集合过大(如 > 1000 项),应分批查询:
- Java 层按每 500~999 个元素拆分 List,循环调用 Mapper
- 或在 XML 中用
<bind>计算批次,但复杂度高,不推荐 - 对超大数据量场景,优先考虑临时表或中间表替代 IN
示例分批逻辑(Java):
List<List<Long>> batches = Lists.partition(ids, 999);
List<User> result = new ArrayList<>();
for (List<Long> batch : batches) {
result.addAll(mapper.selectByIds(batch));
}注意参数类型与 SQL 类型匹配
#{id} 是预编译占位符,类型由 Java 对象决定。若 ids 是 List<String>,且数据库字段是数字类型(如 BIGINT),可能因隐式转换失败或索引失效。务必保证类型一致:
- 数值 ID → 用
Long或Integer集合 - 字符串主键(如 UUID)→ 字段和参数都用
String,SQL 中无需额外引号 - 避免混用基本类型与包装类,防止
null导致空指针
不推荐写 '#{id}' —— 这会绕过预编译,有 SQL 注入风险,且类型校验失效。


















