MyBatis动态SQL

MyBatis能够在Mapper配置XML文件中使用<if><choose>等标签动态拼接SQL语句。实际上,动态拼接SQL不代表我们把软件的业务逻辑搬到了配置文件中,这个功能只是为了让SQL能更好的完成每一个持久层的数据操作任务,因此动态SQL一般有固定的几个应用场景,比如动态查询。XML配置文件中拼接SQL可读性极差,而且完全无法debug,因此不要滥用这个功能。

下面我们简单介绍Mybatis的动态SQL标签的用法。

环境准备

这里我们将以例子的形式介绍动态SQL的写法,使用的数据库表和Java实体类如下。

create table t_user(
    user_id bigint auto_increment,
    username varchar(255) not null,
    email varchar(255) not null,
    password varchar(255) not null,
    primary key(user_id)
);
@Data
public class User {
    private Long userId;
    private String username;
    private String email;
    private String password;
}

if

下面例子中实现的功能是使用<if>实现根据多个动态字段的查询。

public List<User> searchUserByUsernameAndEmail(@Param("username") String username, @Param("email") String email);
<select id="searchUserByUsernameAndEmail" resultType="com.gacfox.demomb.model.User">
  select user_id as userId,username,email,password from t_user
  where 1=1
  <if test="username != null and username != ''">
    and username like concat('%',#{username},'%')
  </if>
  <if test="email != null and email != ''">
    and email like concat('%',#{email},'%')
  </if>
</select>

<if>标签必须有test属性,其中的内容实际上是OGNL表达式(在Struts2章节我们曾介绍过),根据表达式结果为truefalse判断该分支是否拼接到SQL上。

注意:我们在SQL中包含一个where 1=1写法,这是因为每个匹配条件都是and开头的,我们添加了where 1=1作为WHERE子句的起始语句,这样拼接后的SQL不至于语法出错。然而在MyBatis中,where 1=1不是好的写法,推荐使用<where>标签(后文将会介绍)。

choose

if只能实现一个分支判断,choose可以实现多个,类似Java中的Switch...Case...语句。

<choose>
  <when test=""></when>
  <otherwise></otherwise>
</choose>

iftest属性一样,whentest也是OGNL表达式,此外这里when标签可以写多个。

where

这里再次使用之前<if>的例子,将其使用<where>进行改进。

<select id="searchUserByUsernameAndEmail" resultType="com.gacfox.demomb.model.User">
  select user_id as userId,username,email,password from t_user
  <where>
    <if test="username != null and username != ''">
      and username like concat('%',#{username},'%')
    </if>
    <if test="email != null and email != ''">
      and email like concat('%',#{email},'%')
    </if>
  </where>
</select>

<where>标签就是配合动态拼接SQL条件子句使用的。where内部包裹的元素有返回值时,在SQL中将加上一个WHERE子句,否则不加;如果内部包裹的第一个条件元素以ANDOR开头,将其去掉,避免SQL语法错误。

set

<set>标签是配合UPDATE语句使用的。这个标签类比where标签理解即可,如果set包裹的元素有返回值时,就插入一个set;如果内部包裹元素最后以逗号,结尾,将逗号去掉。

trim

实际上面介绍的whereset标签都可以用trim标签实现,trim是一个更加通用的用于辅助动态拼接SQL的标签,下面例子使用<trim>实现了和<set>相同的功能。

<trim prefix="SET" suffixOverrides=","></trim>
  • prefixtrim内部包含内容时,会加上前缀
  • prefixOverridestrim内部包含内容时,会去掉该前缀
  • suffixtrim内部包含内容时,会加上后缀
  • suffixOverridestrim内部包含内容时,会去掉该后缀

foreach

<foreach>标签用于对实现了Iterable接口的Java对象进行遍历,下面例子中我们迭代了一个列表对象,它用于生成一个IN子句的范围。

<foreach collection="idList" open="(" close= ")" separator= "," item="id" index="i">
  #{id}
</foreach>
  • collection:要迭代的属性名
  • open:整个的前缀
  • close:整个的后缀
  • separator:分隔符
  • item:迭代的变量名
  • indexList是当前的索引值,Map是当前的键值

bind

bind标签用于创建一个值并绑定到变量上,比较少用。

<bind name="" value="" />
  • name:创建的变量名
  • value:创建的变量值
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。