专注Java领域技术
我们一直在努力

04. Mybatis 动态sql

原文始发于:04. Mybatis 动态sql

Mybatis 的第三个强大特性便是它的动态SQL, 允许根据传入参数不同, 动态拼接sql. Mybatis 动态sql 功能很强大, 但是标签却很少, 这主要得益于Mybatis 动态表达式使用了Apache 的OGNL 表达式.

1. 动态sql相关标签

Mybatis 的动态sql 功能很强大, 但是标签却比较少. 大致可以分为以下四类:

  • 判断类标签: if, choose, when, otherwise
  • 拼接截断类标签: trime, where, set
  • 循环类标签: foreach
  • 自定义遍历标签: bind

2. 判断类标签

2.1 if

  • test 属性的表达式写法就是ognl 表达式写法
  • 当test 表达式为真时, 拼接sql
  • Mybatis 并没有提供else 标签, 若要实现else 功能, 可以通过test表达式取反, 或choose标签来实现
  • 此处where, 只是演示不借助于标签不优雅写法, 并不推荐使用
<!-- 通过性别查询员工列表, 如果传入sex为空, 则默认查询性别为M 的员工 --> <select id="queryBySex" resultType="EmployeePO">     select * from t_employee     where     <!-- 默认查询sex=M -->     <if test="sex=null or sex=''">          sex = 'M'     </if>     <if test="sex!=null and sex!=''" >         sex = #{sex}     </if> </select> 

2.2 choose(when, otherwise)

  • choose-when 标签是多条件选择标签, 类似于java 中的switch case 结构.
  • choose-otherwise 标签也可以实现if-else 结构

2.2.1 choose 实现if-else 接口

  • 如果传入sex为空, 则查询sex=M的, 否则查询sex=W 的员工列表
  • 此处where 1=1 , 只是演示不借助于标签不优雅写法, 并不推荐使用
<!-- 通过性别查询员工列表, 如果传入sex为空, 则默认查询性别为M 的员工 --> <select id="queryBySex" resultType="EmployeePO">     select * from t_employee     where 1=1     <choose>         <when test="sex=null or sex=''">             and sex = 'M'         </when>         <otherwise>             and sex = 'W'         </otherwise>     </choose> </select> 

2.2.2 choose 实现switch-case 结构

choose-when-otherwise 和Java中的switch-case 结构类似, 只能走一个判断分支, 只要有一个条件匹配之后, 就会中断判断结构.

<!-- 查询员工列表      优先判断name: 如果性别参数name 不为空, 则只拼接name 查询条件      其次判断sex: 如果sex 不为空, 则只拼接sex 查询条件      若以上条件均不满足, 则拼接默认查询条件  --> <select id="query" resultType="EmployeePO">     select * from t_employee where 1=1     <choose>         <when test="name != null and name != ''">             and name like "%"#{name}"%"         </when>         <when test="sex != null and sex != ''">             and sex = #{sex}         </when>         <otherwise>             and entryDate = '2018-05-01'         </otherwise>     </choose> </select> 

2. 截断拼接

从笔者上面的例子中也可以看出, 在进行条件拼接时, 使用where 或where 1=1 的方式并不雅观, 在多个条件时,还可能出错. Mybatis 提供了Where

2.1 where

  • where 标签会智能拼接where 关键字, 当where 标签中, 至少有一个条件满足时, 才会拼接where 关键字
  • where 标签会智能移除最前面的逻辑运算符and或or, 所以每个sql拼接片段前可都加上逻辑运算符and 或 or
  • where 等价实现:
<!-- 查询员工列表     如果name 不为空, 则拼接name 条件,     如果sex 不为空, 则拼接sex 条件.     name 和 sex 条件不再是二选一, 可以同时存在 --> <select id="query2">     select * from t_employee     <where>         <if test="name != null and name != ''">             and name like "%"#{name}"%"         </if>         <if test="sex != null and sex != ''">             and sex = #{sex}         </if>     </where> </select> 

2.2 set

  • set 标签会智能拼接set 关键字, 当set标签中, 至少有一个条件满足时, 拼接set 关键字
  • set 标签会智能去除最后的逗号, 所以每个sql 拼接片段后都添加逗号即可.
  • set 等价实现:
<!-- 更新不为空的属性 --> <update id="updateNotNull">     update t_employee     <set>         <if test="name != null">             name = #{name},         </if>         <if test="sex != null">             sex = #{sex},         </if>         <if test="entryDate != null">             entryDate = #{entryDate},         </if>     </set>     where id = #{id} </update> 

2.3 trim

如果说where标签和set标签的智能拼接set/where 关键字, 智能移除末尾逗号, 或开头的AND 或OR 还不能满足需求, 那么可通过trim 来自定义拼接规则.

  • prefix: 指定智能添加的前缀, 只能添加指的是当trim 包裹的sql 片段不为空时.
  • suffix: 指定智能添加的后缀
  • prefixOverrides: 指定只能删除前面的字符, 只能删除不区分字符串的大小写
  • suffixOverrides: 指定智能删除最后的字符
<!-- where标签的等价实现. 不区分and 和 or 的大小写--> <trim prefix="where" prefixOverrides="ADN | OR  ">  </trim>  <!-- set 标签的等价实现 --> <trim prefix="set" suffixOverrides=","> </trim> 

3. 循环标签-foreach

foreach 是Mybatis 动态标签中的唯一一个循环标签, 常用于集合的遍历. foreach 的属性:

  • collection: 用于遍历的集合/数组的变量名称, 需要注意的是: 数组名为array, 列表为list, 集合为collection
  • open: 遍历列表前,拼接的字符串
  • close: 遍历列表后,拼接的字符
  • separator: 遍历列表时,每个元素之间的间隔字符串
  • item: 每个元素的变量
  • index: 当集合为map时, index 为key, item 为value; 当集合为非map时, index 为索引

3.1 foreach 实现in 查询

  • 需要注意的是, xml 中获取list 是使用的变量list, 与Mapper接口中定义的参数名无关.
  • 不能使用位置参数 arg0, param1, 或则形参名称ids

sql 映射片段:

<!-- 对id 进行in 查询 --> <select id="queryByIds" resultType="EmployeePO">     select * from t_employee     <where>         id in         <foreach collection="list" open="(" separator="," close=")" item="id">             #{id}         </foreach>     </where> </select> 

Mapper 接口定义:

List<EmployeePO> queryByIds(List<Long> ids); 

3.2 foreach 实现批量新增

mysql 中支持values (),(),()… 方式进行批量新增, 所以可以借助于foreach 实现.

<!-- mysql 批量新增 --> <insert id="batchSave" useGeneratedKeys="true" keyProperty="id">     insert into t_employee(id, name, sex, age, entryDate)     values     <foreach collection="list" separator="," item="emp">         (null, #{emp.name}, #{emp.sex}, #{emp.age}, #{emp.entryDate})     </foreach> </insert> 

4. 自定义变量-bind 标签

bind 标签可以在xml 中定义一个变量, 然后再通过#{} 进行引用. 在xml 中#{} 是无法进行动态拼接字符串的, 如拼接like 的%号, 可以借助于bind 进行拼接. bind 标签有两个属性:

  • name: 指定变量名
  • value: 指定变量值, 支持ognl 表达式
<!-- bind 应用于拼接like, 笔者顺带测试一下trime 标签 --> <select id="query" resultType="EmployeePO">     select * from t_employee     <trim prefix="where" prefixOverrides="and | or  ">         <!--定义namePatten 变量,用于模糊匹配 -->         <bind name="namePattern" value="'%' + name + '%'"/>          <!-- 通过#{} 进行引用即可 -->         <if test="name != null and name != ''">             and name like #{namePattern}         </if>         <if test="sex != null and sex != ''">             and sex = #{sex}         </if>     </trim> </select> 

赞(0) 打赏
未经允许不得转载:Java小咖秀 » 04. Mybatis 动态sql
免责声明

抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

专注Java技术 100年

联系我们联系我们

你默默的关注就是最好的打赏~

支付宝扫一扫打赏

微信扫一扫打赏