MyBatis 动态 SQL

动态 SQL 是 MyBatis 的一个强大特性。在编写 SQL 语句时,尝尝需要根据不同条件拼接 SQL 语句,动态 SQL 帮助开发者非常轻松地实现各种条件下的 SQL 拼接。

下面是 MyBatis 提供的基于 OGNL 的动态 SQL 表达式。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

1. if 语句

动态 SQL 中一个常见做法是有条件包含 where 子句。

示例:

<select id = "getByName" parameterType = "User" resultType = "User">
   SELECT * FROM User        
   <if test = "name != null">
      WHERE name LIKE #{name}
   </if> 
</select>

此语句查询用户列表,如果提供了用户名称,则根据用户名(like 匹配)查询用户。

可以包含多个 if 条件,如下所示:

<select id = "getByName" parameterType = "User" resultType = "User">

   SELECT * FROM User        
   <if test = "name != null">
      WHERE name LIKE #{name}
   </if>

   <if test = "id != null">
      AND id = #{id}
   </if> 
</select>

2. choose, when, otherwise 语句

MyBatis 提供了一个 <choose> 标签,类似 Java 的 switch 语句,可以在多个选项中只选择一个生效。

下面的示例,如果 name 不为空,根据 name 查询用户,如为空,接着判断下一个条件:如果 id 不为空,根据 id 查询用户,如果都不满足进入 otherwise 分支。

<select id = "getByNameOrId" parameterType = "User" resultType = "User">
   SELECT * FROM User
   <choose>
      <when test = "name != null">
          WHERE name LIKE #{name}
      </when> 

      <when test = "id != null">
         WHERE id = #{id}
      </when>

      <otherwise>
         WHERE 1 
      </otherwise>

   </choose>

</select>

3. where, set 语句

看前面的例子:

<select id = "getByName" parameterType = "User" resultType = "User">

   SELECT * FROM User        
   <if test = "name != null">
      WHERE name LIKE #{name}
   </if>

   <if test = "id != null">
      AND id = #{id}
   </if> 
</select>

如果前一个条件不满足,后面条件满足,生成的sql语句是错的,如下所示:

SELECT * FROM User
AND id = xxx

mybatis的<where>标签可解决此类问题:

<select id = "getByName" parameterType = "User" resultType = "User">

   SELECT * FROM User
   <where>
       <if test = "name != null">
          name LIKE #{name}
       </if>

       <if test = "id != null">
          AND id = #{id}
       </if> 
   </where>
</select>

<where>标签只在标签内至少有一个条件成立时才插入 where,另外,如果内容以 AND 或 OR 开头,MyBatis 会自动去掉 AND 与 OR。

类似 <where>,动态更新时可以使用 <set>,<set> 标签可以用于动态包含需要更新的列。

示例:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

4. foreach 语句

foreach 的主要作用是遍历一个集合构建 in 条件。例如,有一个用户 List,可以通过 foreach 遍历 List 获取所有用户 id 作为 in 条件。

foreach 标签的属性主要有 item,index,collection,open,separator,close。

  • item 表示遍历集合时的当前元素(如果集合是map,item是值)
  • index 表示遍历集合时的当前元素索引(如果集合是map,item是键)
  • open 表示该语句开始字符串
  • separator 表示语句中元素之间的分隔符
  • close 表示该语句结束字符串
  • collection 表示集合的类型,任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 作为集合参数
<select id = "selectUserIn" resultType = "User" parameterType="java.util.List">
   SELECT *
   FROM User
   WHERE id in

   <foreach item = "item" index = "index" collection = "list"
      open = "(" separator = "," close = ")">
      #{item}
   </foreach>

</select>

5. 动态 SQL 范例

1) UserMapper.xml

映射文件中添加如下代码:

    ...

    <select id="getByName" parameterType="User" resultMap="result">
        SELECT * FROM User

        <if test="name != null">
            WHERE name LIKE #{name}
        </if>

    </select>

    ...

2) App.Java

应用程序 main 类文件中添加如下代码:

System.out.println("------------ 动态sql获取用户 -----------");
User user3 = new User("user3");
user3 = (User) session.selectOne("User.getByName", user3);
System.out.println(user3.getId());
System.out.println(user3.getName());
System.out.println("动态sql获取用户成功");

3) 运行

输出:

------------ 动态sql获取用户 -----------
3
user3
动态sql获取用户成功

下一章:MyBatis 注解开发

MyBatis 最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到了 MyBatis3 提供了新的基于注解的配置。我们可以使用 XML 方式编写 SQL 映射语句,实现对数据库的增删改查操作。MyBatis 提供另外一种方式,使用 Java 注解编写 SQL 映射语句。