详解四种mybatis动态标签使用-if, choose, trim, foreach

阅读说明:

  1. 如果有排版格式问题,请移步www.yuque.com/mrhuang-ire... 《详解四种mybatis动态标签使用-if, choose, trim, foreach》,选择宽屏模式效果更佳。
  2. 本文为原创文章,转发请注明出处。如果觉得文章不错,请点赞、收藏、关注一下,您的认可是我写作的动力。

简介

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时减少语法踩坑。

参考文档:

mybatis.org/mybatis-3/d...

相关推荐
向阳121815 小时前
mybatis 动态 SQL
数据库·sql·mybatis
新手小袁_J16 小时前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
xlsw_1 天前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
cmdch20171 天前
Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题
数据库·sql·mybatis
秋恬意1 天前
什么是MyBatis
mybatis
CodeChampion1 天前
60.基于SSM的个人网站的设计与实现(项目 + 论文)
java·vue.js·mysql·spring·elementui·node.js·mybatis
ZWZhangYu2 天前
【MyBatis源码分析】使用 Java 动态代理,实现一个简单的插件机制
java·python·mybatis
程序员大金2 天前
基于SSM+Vue的个性化旅游推荐系统
前端·vue.js·mysql·java-ee·tomcat·mybatis·旅游
奔跑草-3 天前
【服务器】MyBatis是如何在java中使用并进行分页的?
java·服务器·mybatis
秋恬意3 天前
接口绑定有几种实现方式
mybatis