Mybatis中动态Sql的基础使用

164 阅读2分钟

前言

动态sql是Mybatis的一大特性,解决了拼接Sql的各种问题,需要学习以下几种常见的元素种类:

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

if

见文知意,if元素使用,多用在where条件下,比如说:

场景一:如下,查找符合要求的blog,但是无法判断是否存在tltle条件;

<select id="findActiveBlogWithTitleLike"
  resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

场景二:同样的情况,但是处理的是多条件

<select id="findActiveBlogWithTitleLike" resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="date != null and  date.day != null">
    and date like #{date.day}
  </if>
</select>

在 MyBatis 中,test 属性是用于判断是否执行相应 SQL 片段的条件表达式的关键属性。它的名字是 MyBatis 约定俗成的,因此它不能被改成其他的名字。

choose、when、otherwise

使用场景:在上面的这个情况下,按照先后顺序,如果存在title就按照title找,不存在则按照date找,如果还不存在,则直接要求搜索出默认id为1的blog。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
AND (
  title LIKE #{title}
  OR (author_name LIKE #{author.name} AND author_name IS NOT NULL)
  OR featured = 1
);

trim、where、set

还是上述的场景,如果说多个条件都不一定存在,通过where元素和if元素解决。where会自动处理掉,前面的and 或者 or。

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG 
  <where>
    <if test="state != null">state = #{state}</if>
    <if test="title != null">AND title LIKE #{title}</if>
    <if test="author != null and author.name != null">AND author_name LIKE #{author.name}</if>
  </where>
</select>

set元素可以进行动态sql的更新,比如说上述场景,更新title,但是author保持不变。

<select id="findActiveBlogLike"
  resultType="Blog">
  SELECT * FROM BLOG 
  <set>
    <if test="state != null">state = #{state}</if>
    <if test="title != null">AND title LIKE #{title}</if>
    <if test="author != null and author.name != null">AND author_name LIKE #{author.name}</if>
  </set>
</select>

trim自定义元素,比如说自定义where功能,或者自定义set功能。

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>
<trim prefix="SET" suffixOverrides=",">
  ...
</trim>
<insert id="create" parameterType="Map">
  <selectKey keyProperty="baseAddress.id" resultType="java.lang.String" order="BEFORE">
    select uuid() from dual
  </selectKey>
  INSERT INTO base_address
  <trim prefix="(" suffix=")" suffixOverrides=",">
    <foreach collection="columns" item="column" separator=",">
      ${column}
    </foreach>
  </trim>
  <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
    <foreach collection="values" item="value" separator=",">
      #{value}
    </foreach>
  </trim>
</insert>

foreach

foreach可以使用于所有可以迭代的集合,比如set,list均可。在其中,index是索引,item是集合项,允许指定开头和结尾的字符串以及集合迭代之间的分隔符,但是也不会错误添加分隔符号。

当迭代的对象是数组的时候,index是迭代的序号,item是本次迭代的元素,当使用Map对象的时候,index是键,item是值。

<select id = "selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  <where>
    <foreach item = "item" index = "index" collection="list"
      open="ID in (" separator="," close=")" nullable = "true">
      #{item}
    <foreach>
  <where>
<select>

script

要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

@Update({"<script>",
      "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}",
      "</script>"})
    void updateAuthorValues(Author author);

bind

bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>