MyBatis 动态 SQL(二):set / trim / foreach

上一章的 if/where 解决"可选条件查询",这一章处理另外两个高频场景:动态更新(只更新非空字段)与批量操作(IN 条件、批量插入)。主角是 set、trim、foreach。

set:动态更新,自动去尾逗号

需求:只更新传入的非空字段。直接用 if 拼 SET 子句,最后一个条件后面会多一个逗号——set 标签自动修剪:

<update id="updateSelective" parameterType="user">
    UPDATE user
    <set>
        <if test="name != null and name != ''">name = #{name},</if>
        <if test="age != null">age = #{age},</if>
    </set>
    WHERE id = #{id}
</update>
  • 至少一个条件成立时,set 输出 SET 前缀并去掉末尾多余的逗号
  • 所有条件都不成立时会拼成 UPDATE user WHERE ...(缺 SET 子句、语法错误),调用方要保证至少传一个可更新字段。

trim:万能修剪器

trim 是 where/set 的"通用版",四个属性:

属性作用
prefix / suffix在拼接结果前/后追加内容
prefixOverrides去掉结果开头的关键字(多个用 | 分隔)
suffixOverrides去掉结果结尾的关键字(如逗号)
官方文档给出的等价关系:wheretrim prefix="WHERE" prefixOverrides="AND |OR "settrim prefix="SET" suffixOverrides=","。自己写一个去掉开头 AND 的例子:
<select id="selectByCondition" resultType="user">
    SELECT id, name, age FROM user
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
        <if test="name != null and name != ''">AND name = #{name}</if>
        <if test="age != null">AND age = #{age}</if>
    </trim>
</select>

foreach:IN 条件与批量插入

场景一:IN (...)——open/close 定首尾,separator 定分隔符:

<select id="selectByIds" resultType="user">
    SELECT id, name, age FROM user
    WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>
List<User> list = userMapper.selectByIds(Arrays.asList(1, 2, 3));

场景二:批量插入——item 是循环变量名,元素内用 #{item.属性} 引用:

<insert id="batchInsert">
    INSERT INTO user(name, age) VALUES
    <foreach collection="list" item="u" separator=",">
        (#{u.name}, #{u.age})
    </foreach>
</insert>

collection 到底填什么? 参数是集合且没加 @Param:List 填 list(或 collection)、数组填 array;加了 @Param("ids") 则填注解名;遍历 Map 时填其 key(item 为 value、index 为 key)。index 属性表示下标,多数场景可省略。建议一律用 @Param 显式命名,别依赖默认名。

组合使用示例

动态更新 + 条件删除经常叠着用:外层 where 控条件、内层 foreach 拼 id 列表,各标签互不冲突,可自由嵌套:

<delete id="deleteByCondition">
    DELETE FROM user
    <where>
        <if test="name != null and name != ''">AND name = #{name}</if>
        <if test="ids != null and ids.size() > 0">
            AND id IN
            <foreach collection="ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
</delete>

小结

set 管动态更新(去尾逗号)、trim 是通用修剪器(where/set 的本质)、foreach 管 IN 与批量插入。配合 if/where,动态 SQL 已能覆盖绝大多数业务拼接需求。

笔记加载中…