前言
动态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>