1、动态SQL语句
在之前我们了解过 Mybatis 的映射文件,那些 SQL 语句都是比较简单的。但有些时候业务逻辑复杂时,我们的 SQL是需要动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。动态 SQL 是 MyBatis 的强大特性之一,MyBatis 3 精简用于动态 SQL 语句元素种类,现在主要了解的元素如下:if
标签、choose (when, otherwise)
标签、trim (where, set)
标签和foreach
标签
2、if 标签
我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
<select id="findByCondition" parameterType="user" resultType="user">
select * from User where
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null and username!= '' ">
and username=#{username}
</if>
</select>
在上述代码中,如果 id 的属性值不为 0 ,则将 and id=#{id}
添加到SQL 语句后,如果 username 的属性值不为 null 且不为 ‘’ 时,则将 and username=#{username}
添加到SQL 语句后。其中 test
属性就是判断条件。
2、choose、when和otherwise 标签
在有些时候,我们只想在多个条件中选择一个使用。就像 java 中的 switch 语句,一个值只匹配一种结果。在 java 的 switch 语句中有三个关键字:switch、case、default
,而 MyBatis 中的也有类似标签, choose、when和otherwise
元素分别与之对应。
<select id="findByCondition" parameterType="user" resultType="user">
select * from User where 1 = 1
<choose>
<when test="age > 12">
AND age = #{author.name}
</when>
<when test="age < 12">
AND age = 0
</when>
<otherwise>
AND age = 120
</otherwise>
</choose>
</select>
上述代码中,判断 age 的属性值,当 age >12 时使用AND age = #{author.name}
,当age < 12 时使用AND age = 0
,当age = 12 时使用默认语句AND age = 0
。
3、trim、where和set 标签
在使用if
标签时,我们可能会遇到这种问题,当 id 和 username 都不满足条件时,SQL 语句会变成这样:select * from User where
;当 id 不满足条件时,SQL 语句会变成这样:select * from User where and username=#{username}
,这样导致查询失败。
为了解决这类问题, MyBatis 就提供一个where
元素标签。where
元素只会在子元素返回任何内容的情况下才插入 “WHERE”
子句。而且,若子句的开头为 “AND” 或 “OR
”,where
元素也会将它们去除:
<select id="findByCondition" parameterType="user" resultType="user">
select * from User
<where>
<if test="id!=0">
id=#{id}
</if>
<if test="username!=null and username!= '' ">
and username=#{username}
</if>
</where>
</select>
上述代码的执行流程时:判断 id 属性和 username 属性是否满足条件,如果都不满足则不添加 where
子句;如果只有其中一个属性或两个属性都满足条件,则添加 where
子句。当只有 username 属性满足条件时,会将子句的开头为 and
直接去除。
还有另外一个元素set
,它主要用于动态包含需要更新的列,使用方法和where
元素一样:
<update id="updateUser">
update Author
<set>
<if test="name != null">name =#{name },</if>
<if test="age != null">age=#{age},</if>
</set>
where id=#{id}
</update>
当然如果where
元素的功能不够,我们也可以通过trim
元素进行自定义,例如在 insert 语句中我们需要自定义插入选项:
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name!= null">
#{name},
</if>
<if test="age!= null">
#{age},
</if>
</trim >
上述代码的执行流程,判断 id 属性和 username 属性的属性值,然后将prefix
属性的属性值添加在子句最前面,suffix
属性的属性值添加在子句最后面,suffixOverrides
属性的属性值表示将子句最后的,逗号
去除,子句的中间部分由if
元素进行判断。
trim
元素还有第四个属性值prefixOverrides
,表示将子句开头的指定属性值去掉。suffixOverrides
和prefixOverrides
的作用是一样的,只不过作用的地方不同,且可以通过 | 或
指定多个属性值。
通过用 trim
元素替换元素和
元素
set
元素和where
元素等价的 trim
元素:
<!-- prefixOverrides属性值中间的空格不能省略 -->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<trim prefix="SET" suffixOverrides=",">
...
</trim>
4、foreach 标签
foreach
标签顾名思义就是用于循环,一般用于构建 IN 条件语句和多条语句插入的场景。任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象都可以作为集合参数传递给 foreach
标签。foreach
标签有几个属性值:
collection
:用于指定集合类型open
:用于指定子句的开头close
:用于指定子句的结尾separator
:用于指定集合每个元素之间的分隔符item
:用于指定循环的当前集合项id
:当使用可迭代对象或者数组时,index 是当前迭代的序号。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
<!--
SELECT * FROM USER WHERE age IN (XX,XX)
-->
<select id="findByAge" resultType="user">
select * from User where age in
<foreach item="item" index="index" collection="array"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
<!--
insert into user (name,age) values (XX,XX),(XX,XX)
-->
<insert id="insertUser" parameterType="user">
insert into user (name,age) values
<foreach item="item" index="index" collection="list"
open="(" separator="),(" close=")">
#{item.name},#{item.age}
</foreach>
</insert>