MyBatis choose 和 bind

1. 前言

在上一小节中,我们介绍了 MyBatis 动态 SQL 中最基础的标签——if 标签,本小节我们将一起学习 choose 和 bind 标签。

choose 标签是 if 标签的增强版,适用于更加复杂的条件判断逻辑;而bind 标签则可以在 OGNL 上下文环境中新绑定一个变量,供后面的 SQL 使用。

2. 定义

慕课解释:choose 标签相当于编程语言 if…else 语句,用于动态 SQL 中的多条件判断,是 if 标签的增强版。

bind 标签可以在动态 SQL 中通过 OGNL 表达式来创建一个新的变量绑定到上下文中,供后续的 SQL 使用。

3. 实例

下面是一个融合了 choose 和 bind 标签的实例:

<select id="selectUserByLikeName" resultType="com.imooc.mybatis.model.User">
  SELECT * FROM imooc_user
  WHERE username LIKE
  <choose>
    <when test="_databaseId == 'mysql'">
      CONCAT('%',#{username},'%')
    </when>
    <when test="_databaseId == 'postgre'">
      '%' || #{username} || '%'
    </when>
    <otherwise>
      <bind name="usernameLike" value="'%' + username + '%'"/>
      #{usernameLike}
    </otherwise>
  </choose>
</select>

通过 choose 标签来判断当前的数据库厂商,如果是 MySQL 数据库,则调用CONCAT函数来拼接 % 和 username,如果是 PostgreSQL 数据库,则使用操作符||来拼接,如果是其它类型的数据库,则直接通过 OGNL 表达式来绑定一个新的变量 usernameLike。

在这个例子中,choose 是一个条件选择标签,第一个 when 相当于 if 判断,第二个 when 相当于 else if,最后的 otherwise 相当于 else。比起 if 标签,choose 标签无疑更为易用,适用于同一条件的多次判断逻辑。

4. 实践

4.1 例1. 多条件查询用户

请使用 MyBatis 完成对 imooc_user 表多条件查询用户的功能,如果 id 不为空则直接使用 id 查询用户,否则使用 username 查询用户,如果 username 也为空,则直接查询全部用户。

分析:

按照 MyBatis 的开发模式,需先在 UserMapper.xml 文件中添加多条件查询用户的 select 标签,然后在 UserMapper.java 中添加上对应的方法。

步骤:

首先,在 UserMapper.xml 中添加 select 标签,并在标签中写入 SQL,使用 choose 中的 when 标签来依次判断 id 和 username 是否为 null,若均为 null,则在 otherwise 中添加上一个永假的值。如下:

<select id="selectUserByIdOrName" resultType="com.imooc.mybatis.model.User">
  SELECT * FROM imooc_user
  WHERE
  <choose>
    <when test="id != null">
      id = #{id}
    </when>
    <when test="username != null">
      username = #{username}
    </when>
    <otherwise>
      1 = 0
    </otherwise>
  </choose>
</select>

这里使用了1 = 0作为条件判断的永假值。

然后在 UserMapper.java 中添加上对应的接口方法,方法接受 id 和 username 两个参数,都可为空。

package com.imooc.mybatis.mapper;

import org.apache.ibatis.annotations.Mapper;
import com.imooc.mybatis.model.User;

@Mapper
public interface UserMapper {
   User selectUserByIdOrName(@Param("id") Integer id, @Param("username") String username);
}

结果:

通过如下代码,我们运行 selectUserByIdOrName 这个方法。

UserMapper userMapper = session.getMapper(UserMapper.class);
User pedro = userMapper.selectUserByIdOrName(null, null);
System.out.println(pedro);

id 和 username 两个属性均为空,因此所执行的 SQL 为:

SELECT * FROM imooc_user WHERE 1 = 0 

成功后,结果为:

null

4.2 例2. 查询小写名称客户

请使用 MyBatis 完成对 imooc_user 表查询小写名称客户的功能,将名称小写后再进行查询。

分析:

同上。

步骤:

首先,在 UserMapper.xml 中添加 select 标签,并在标签中写入 SQL,使用 bind 标签将参数小写化成一个新的变量 lowercaseName。

<select id="selectUsernameLowercase" resultType="com.imooc.mybatis.model.User">
  <bind name="lowercaseName" value="username.toLowercase"/>
  SELECT * FROM imooc_user
  WHERE username = #{lowercaseName}
</select>

然后在 UserMapper.java 中添加上对应的接口方法,方法接受 username 一个参数。

package com.imooc.mybatis.mapper;

import org.apache.ibatis.annotations.Mapper;
import com.imooc.mybatis.model.User;

@Mapper
public interface UserMapper {
   User selectUsernameLowercase(String username);
}

结果:

通过如下代码,我们运行 selectUsernameLowercase 这个方法。

UserMapper userMapper = session.getMapper(UserMapper.class);
User pedro = userMapper.selectUsernameLowercase("PEDRO");
System.out.println(pedro);

成功后,结果为:

User{id=2, username='pedro', age=24, score=200}

5. 小结

  • bind 标签虽然可以通过 OGNL 表达式在上下文中绑定一个新的变量,但在实际应用所见不多,我们希望在代码层面上处理好参数,这样既方便维护,也更有利于迁移。
  • choose 标签是一个增强版的 if 标签,适用于更加复杂的逻辑判断场景。