mybatis批量查询多条件

在 MyBatis 中编写 IN 子句,最核心的工具是 <foreach> 标签。根据您的需求,通常分为两种场景:单字段 IN(如 id IN (1,2,3))和 多字段组合 IN(如 (id, name) IN ((1,'张三'), (2,'李四')))。


1. 单字段 IN(最常见)

如果您只是传入一个 List 或数组,查询某个字段是否在集合中:

Java 接口:

Java

List<User> selectByIds(@Param("idList") List<Long> idList);

XML 映射文件:

XML

<select id="selectByIds" resultType="User">
    SELECT * FROM sys_user
    WHERE id IN
    <foreach collection="idList" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

2. 多字段组合 IN (Tuple IN)

如果您需要同时匹配多个字段(例如:根据“编码”和“类型”两个维度锁定一组数据),可以使用 SQL 的元组语法。

Java 接口:

Java

// 假设 ProductDTO 包含 id 和 category 属性
List<Product> selectByCompositeKeys(@Param("productList") List<ProductDTO> productList);

XML 映射文件:

XML

<select id="selectByCompositeKeys" resultType="Product">
    SELECT * FROM product
    WHERE (id, category) IN
    <foreach collection="productList" item="item" open="(" separator="," close=")">
        (#{item.id}, #{item.category})
    </foreach>
</select>

注:这种语法在 MySQL、PostgreSQL、Oracle 中通常支持良好,但在 SQL Server 中可能不支持,需要改写为多组 OR 连接。


3. <foreach> 标签参数详解

为了确保代码不出错,理解这几个属性非常重要:

属性说明
collection必须。指定传入的集合参数名。若没用 @Param,List 默认为 list,数组为 array
item必须。集合中元素迭代时的别名,在 #{} 中使用。
open循环开始时的字符串(通常是 ()。
separator每次循环之间的分隔符(通常是 ,)。
close循环结束时的字符串(通常是 ))。
index可选。当前迭代的索引值(Map 时为 Key)。

💡 进阶避坑指南

1. 集合为空的判空处理

如果 idList 为空,生成的 SQL 会变成 WHERE id IN (),这会导致 SQL 语法错误。

建议写法:

XML

<where>
    <if test="idList != null and idList.size() > 0">
        AND id IN
        <foreach collection="idList" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </if>
    <if test="idList == null or idList.size() == 0">
        AND 1 = 0  </if>
</where>

2. 集合长度限制

  • MySQL: max_allowed_packet 限制了 SQL 的大小,虽然可以设置很大,但 IN 里的元素过多(如超过 1000 个)会导致性能急剧下降。
  • Oracle: IN 列表中的表达式数量硬限制为 1000 个。
  • 方案: 如果数据量极大,建议分批查询,或者将数据插入临时表进行 JOIN 查询。

3. 性能优化

如果您只需要查询一个字段且不需要去重,直接使用 IN 即可。但如果列表非常长,考虑使用 EXISTS 配合子查询,有时性能会更优。

您目前的列表数据量大概在什么级别?如果超过 1000 条,我建议为您提供分批处理的代码示例。

微信公众号        

欢迎关注公众号

上一篇
下一篇