where、set、trim用法

这 3 个标签解决了类似的问题,并且 where 和 set 都属于 trim 的一种具体用法。下面分别来看这 3 个标签。

where用法

where 标签的作用:如果该标签包含的元素中有返回值,就插入一个 where;如果 where 后面的字符串是以 AND 和 OR 开头的,就将它们剔除。

首先修改 UserMapper.xml 中的 selectByUser 方法,注意这个方法在4.1.1节中的用法。此处将这个方法改成使用 where 标签,代码如下。

<select id="selectByUser" resultType="tk.mybatis.simple.model.SysUser">
    select id,
        user_name userName,
        user_password userPassword,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
    from sys_user
    <where>
        <if test="userName != null and userName != ''">
            and user_name like concat('%',#{userName},"%")
        </if>
        <if test="userEmail != null and userEmail != ''">
            and user_email = #{userEmail}
        </if>
    </where>
</select>

当 if 条件都不满足的时候,where 元素中没有内容,所以在 SQL 中不会出现 where,也就不存在4.1.1节中 SQL 错误的问题。如果 if 条件满足,where 元素的内容就是以 and 开头的条件,where 会自动去掉开头的 and,这也能保证 where 条件正确。和4.1.1节中相比,这种情况下生成的 SQL 更干净、更贴切,不会在任何情况下都有 where 1=1 这样的条件。

set用法

set 标签的作用:如果该标签包含的元素中有返回值,就插入一个 set;如果 set 后面的字符串是以逗号结尾的,就将这个逗号剔除。

修改 UserMapper.xml 中的 updateByIdSelective 方法,注意和4.1.2节中的区别,代码如下。

<update id="updateByIdSelective">
    update sys_user
    <set>
        <if test="userName != null and userName != ''">
            user_name = #{userName},
        </if>
        <if test="userPassword != null and userPassword != ''">
            user_password = #{userPassword},
        </if>
        <if test="userEmail != null and userEmail != ''">
            user_email = #{userEmail},
        </if>
        <if test="userInfo != null and userInfo != ''">
            user_info = #{userInfo},
        </if>
        <if test="headImg != null">
            head_img = #{headImg,jdbcType=BLOB},
        </if>
        <if test="createTime != null">
            create_time = #{createTime, jdbcType=TIMESTAMP},
        </if>
        id = #{id},
    </set>
    where id = #{id}
</update>

在 set 标签的用法中,SQL 后面的逗号没有问题了,但是如果 set 元素中没有内容,照样会出现 SQL 错误,所以为了避免错误产生,类似 id=#{id} 这样必然存在的赋值仍然有保留的必要。从这一点来看,set 标签并没有解决全部的问题,使用时仍然需要注意。

trim用法

where 和 set 标签的功能都可以用 trim 标签来实现,并且在底层就是通过 TrimSqlNode 实现的。

where 标签对应 trim 的实现如下。

<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>

这里的 AND 和 OR 后面的空格不能省略,为了避免匹配到 andes、orders 等单词。

实际的 prefixeOverrides 包含 “AND”、“OR”、“AND\n”、“OR\n”、“AND\r”、“OR\r”、“AND\t”、“OR\t”,不仅仅是上面提到的两个带空格的前缀。

set 标签对应的 trim 实现如下。

<trim prefix="SET" suffixOverrides=",">
...
</trim>

trim 标签有如下属性。

  • prefix:当 trim 元素内包含内容时,会给内容增加 prefix 指定的前缀。

  • prefixOverrides:当 trim 元素内包含内容时,会把内容中匹配的前缀字符串去掉。

  • suffix:当 trim 元素内包含内容时,会给内容增加 suffix 指定的后缀。

  • suffixOverrides:当 trim 元素内包含内容时,会把内容中匹配的后缀字符串去掉。