MyBatis 动态 SQL(一):if / where / choose

查询条件"有时有、有时没有"是常态:按名字搜、按年龄区间搜、还是两个条件一起搜?用字符串拼接会写成一场灾难。MyBatis 的动态 SQL 标签(if、where、choose…)让你在 XML 里按条件拼 SQL,干净又安全。

一个典型的"可选条件"需求

下面的查询要求:name 传了就按 name 过滤,age 传了就按 age 过滤,都不传就查全部。

if:条件成立才拼接

<select id="selectByCondition" resultType="user">
    SELECT id, name, age FROM user
    WHERE 1 = 1
    <if test="name != null and name != ''">
        AND name = #{name}
    </if>
    <if test="age != null">
        AND age = #{age}
    </if>
</select>

test 里是 OGNL 表达式,常见写法:判 null、判空串、比较大小(age &gt; 18 注意 XML 转义)。先写 WHERE 1 = 1 是偷懒做法,能让后面的 AND 永远成立,但不优雅,更推荐下面的 where。

where:自动去掉多余 AND/OR

<select id="selectByCondition" resultType="user">
    SELECT id, name, age FROM user
    <where>
        <if test="name != null and name != ''">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>
  • 所有条件都不成立时,where 什么都不输出(不会有裸 WHERE)。
  • 至少一个条件成立时,where 会自动去掉开头的 AND/OR,输出规范的 WHERE 子句。
  • 原理:where 等价于 trim 的快捷写法(prefix="WHERE",prefixOverrides="AND |OR "),第 9 章讲 trim 时再展开。

choose / when / otherwise:多选一

if 是"各自独立可叠加",choose 则是"多个分支只命中第一个"(类似 Java 的 switch):

<select id="selectByKeyword" resultType="user">
    SELECT id, name, age FROM user
    <where>
        <choose>
            <when test="name != null and name != ''">
                AND name = #{name}
            </when>
            <when test="age != null">
                AND age = #{age}
            </when>
            <otherwise>
                AND id > 0   <!-- 兜底分支,可省略 -->
            </otherwise>
        </choose>
    </where>
</select>

执行逻辑:从上到下找第一个 test 为真的 when,执行它并跳过其余分支;一个都不满足时执行 otherwise。

其他常用标签:bind

bind 可以在 SQL 里先加工参数,比如模糊查询的 %关键字%

<select id="selectByNameLike" resultType="user">
    <bind name="likeName" value="'%' + name + '%'"/>
    SELECT id, name, age FROM user
    WHERE name LIKE #{likeName}
</select>

常见坑

  • 判空要完整:字符串建议 != null and != '',只判 null 时空串仍会拼出错误条件。
  • test 是 OGNL:不支持的部分 Java 语法(如直接调用任意方法)在 test 里不可用,写法以官方文档为准。
  • XML 里的小于号要转义:写 age &lt; 18 或把比较逻辑放进 &lt;&gt; 转义中,直接写 < 会导致 XML 解析失败。

小结

动态条件三板斧:可叠加用 if(配合 where 去多余 AND/OR)、多选一用 choose/when/otherwise、加工参数用 bind。下一章继续 set/trim/foreach,解决更新与批量的动态拼接。

笔记加载中…