阅读说明:
- 如果有排版格式问题,请移步www.yuque.com/mrhuang-ire... 《详解四种mybatis动态标签使用-if, choose, trim, foreach》,选择宽屏模式效果更佳。
- 本文为原创文章,转发请注明出处。如果觉得文章不错,请点赞、收藏、关注一下,您的认可是我写作的动力。
简介
MyBatis其中一个强大的功能是支持动态SQL功能,它能够协助你方便地拼接SQL。今天来再次温习下mybatis中四种常用的动态标签:if, choose, trim, foreach。
if
顾名思义,if用来做条件判断,最常用的方法是在where语句中拼接查询语句。看个简单示例:
ini
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
</select>
这个sql支持可选文本搜索类型功能。如果你没有输入任何标题,那么所有活跃博客都会被返回。sql如下:
sql
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
但如果你输入了一个标题,它会过滤出符合这样的标题。sql如下:
sql
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
AND title like #{title}
当然,还可以多个if条件动态拼接。
ini
select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
这里if里面条件判断式title != null语义为不为空,当然还有其他的用法,下面进行了整理。
通用
- eq 或者 ==:等于。
xml
<if test="username != null and 'hello' == username"></if> <!-- 如果userName为hello字符串 -->
<if test="username != null and 'hello' eq username"></if> <!-- 如果userName为hello字符串 -->
这里特别注意,如果字符串是单个字符,比如:
bash
<if test="username != null and 'A' == username"></if>
会被mybatis判断为字符串与字符比较,会报错。正确写法是:
bash
<if test="username != null and 'A'.toString() == username"></if>
- neq或者 !=: 不等于。
xml
<if test="username != null"> <!-- 如果username不为空 -->
<if test="username != null and '' != username"></if> <!-- 如果username不为空串 -->
<if test="username != null and '' neq username"> <!-- 如果username不为空串 -->
<if test="username != null and 'hello' != username"></if> <!-- 过滤hello字符串 -->
<if test="username != null and 'hello' neq username"></if> <!-- 过滤hello字符串 -->
- 逻辑: and, or, ||, 不支持&&
xml
<if test='id != null and id > 28'></if> <!-- 如果id不为空并且大于28 -->
数字
- gt或者>: 大于。
xml
<if test='id != null and id > 28'></if><!--如果 id > 28 -->
<if test='id != null and id gt 28'></if><!--如果 id > 28 -->
- gte或者>=:大于或者等于
xml
<if test='id != null and id >= 28'></if><!--如果 id >= 28 -->
<if test='id != null and id gte 28'></if><!--如果 id >= 28 -->
- lt:小于,直接使用<会报错,相关联的 "test" 属性值不能包含 '<' 字符,
xml
<if test='id != null and id lt 28'></if><!--如果 id < 28 -->
- lte:小于或者等于,直接使用<=会报错,相关联的 "test" 属性值不能包含 '<=' 字符
xml
<if test='id != null and id lte 28'></if><!--如果 id <= 28 -->
字符串
- indexOf(): 查找指定字符串最开始出现位置
xml
<if test="username != null and username.indexOf('ji') == 0"> </if> <!-- 是否以什么开头 -->
<if test="username != null and username.indexOf('ji') >= 0"> </if> <!-- 是否包含某字符 -->
- lastIndexOf(): 查找指定字符串最后出现位置
xml
<if test="username != null and username.lastIndexOf('ji') > 0"></if> <!-- 是否以什么结尾 -->
集合
- isEmpty(): 判断是否为空
xml
<if test="userList != null and userList.isEmpty()"></if> <!-- userList不为空 -->
- size(): 获取集合大小
xml
<if test="userList != null and userList.size()>0"></if> <!-- userList不为空 -->
map
map.key: 获取key对应的值,map为使用方法中的别名。
xml
List<Object> select(@Param("map")Map map); //接口定义
<if test="map.item != null"></if> <!-- map中item对应键值不为空 -->
choose(when, otherewise)
choose标签类似于java语法中的switch..case...default,依次按照顺序检查when标签中的判断条件是否成立,如果有一个成立,则拼接对应的SQL执行, 不再检查剩余when标签。如果都不成立,则拼接otherwise中的SQL语句。
- choose: 对应switch
- when: 对应case
- otherwise: 对应default
ini
<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>
trim(where ,set)
mybatis支持动态SQL, 使用trim能够拼凑的SQL语句进行修剪。标签如下:
- prefix: 添加指定前缀;
- prefixOverrides: 去掉首部内容,示例"AND"表示移除首部AND字样, "AND | OR"表示语出首部AND, OR字样
- suffix: 添加指定后缀;
- suffixOverrides: 去掉尾部内容;
先来看个sql:
ini
<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>
</select>
如果where中,如果一个条件都没有命中的话,sql将变成:
sql
SELECT * FROM BLOG
WHERE
如果where中,只有第二个条件命中,sql将变成:
sql
SELECT * FROM BLOG
WHERE
AND title like 'someTitle'
这两种场景都会有问题,使用trim可以解决。使用trim标签prefixOverrides移除多余的AND, 并且所有if都不满足,trim会无效,sql上面不会出现trim标签的内容。改造方案如下:
ini
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<trim prefix ="WHERE" prefixoverride="AND | OR">
<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>
</trim>
</select>
当然,使用标签也能解决问题,它能够智能识别上述两种异常场景。
bash
<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。
foreach
foreach用户集合遍历,包括List, Array, Map。foreach参数如下:
- item: 用于表示在迭代过程中,每次迭代到的元素;
- index: 用于表示在迭代过程中,每次迭代到的位置;
- collection: 该属性必填,有三种格式:list, array, map, 按照传递参数类型填写对应格式。
- open: 表示该语句以什么开始;
- separator: 表示在每次进行迭代之间以什么符号作为分隔符;
- close: 表示以什么结束;
示例:
perl
<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>
总结
mybatis是我们工作中经常接触的数据库框架,mybatis丰富的动态标签协助我们写出更好的SQL语句。本文总结了mybatis中四种常用的动态标签:if, choose, trim, foreach的用法,写sql时减少语法踩坑。