在XML 中支持的几种标签:  • if  • choose、when、otherwise  • where  • set  trim   • foreach


OGNL 表达式

1. el or e2
2. el and e2
3. el == e2 或 el eq e2
4. el != e2 或 el neq e2
5. el lt e2 :小于
6. el lte e2 :小于等于,其他表示为gt(大于)、gte(大于等于)
7. el + e2 、el - e2 、e1 * e2 、e 1 / e2 、el % e2
8. !e 或 not e :非,取反
9. e.method(args) : 调用对象方法
JO. e.property: 对象属性值
11. el[e2]:按索引取值(List、数组和Map)
12. @class@method(args):调用类的静态方法
13. @class@field:调用类的静态字段值
map['userName']或map.userName来获取map中key为userName的值。

< if test= "@tk.mybatis.util.StringUtil@isNotEmpty(userName)">
  and user_name like concat('%', #{userName}, '%')
</if>
其中StringUtil 类如下:
public class StringUtil {
  public static boolean isEmpty(String str) {
    return str == null || str.length() == 0;
  }

  public static boolean isNotEmpty(String str) {
   return !isEmpty(str) ;
  }
}


if 标签有一个必填的属性test, test 的属性值是一个符合OGNL 要求的判断表达式,表达式的结果可以是true 或false ,除此之外所有的非0 值都为true ,只有0 为false。

条件查询
1、判断条件property != null 或property == null,适用于任何类型的字段,用于判断属性值是否为空。
2、判断条件property != '' 或 property == '', 仅适用于String 类型的宇段,用于判断是否为空字符串。
3、判断条件list != null and list.size()>0,判断一个集合是否为空。
4、当有多个判断条件时,使用and 或or 进行连接,嵌套的判断可以使用小括号分组,and 相当于Java 中的与(&&),or 相当于Java 中的或(||)。
条件查询
<select id="">
select * from sys_user where 1 = 1
<if test= "userName != null and userName != '' ">
  and user_name like concat('%', #{userName}, '%')
</if>
<if test = "userEmail != null and userEmail !='' " >
  and user_email = #{userEmail}
</if>
</select>
1 = 1 有两个作用,作用1:防止报错;作用2:全表查询。

条件更新
现在要实现这样一个需求,只更新有变化的字段。更新的时候不能将原来有值但没有发生变化的字段更新为空或null。通过if标签可以实现这种动态列更新。
<update id="">
update sys_user set
<if test="userName != null and userName !='' ">
  user_name= #{userName},
</if>
<if test="userPassword != null and userPassword !='' ">
  user_password= #{userPassword},
</if>
<if test="userEmail != null and userEmail != '' ">
  user_email = #{userEmail},
</if>
  id = #{id}
where id = #{id}
</update>
注意:where 关键字前面的id = #{id},防止报错。
1、如果全部条件都为空或null,sql就是 --> update sys_user set where id = #{id}。
2、查询条件只有一个不是null 也不是空(假设是userName),sql就是 --> update sys_user set user_name= #{userName}, where id= #{id}

条件插入
在数据库表中插入数据的时候,如果某一列的参数值不为空,就使用传入的值,如果传入参数为空,就使用数据库中的默认值,而不使用传入的空值。使用if也可以实现这种动态插入列的功能。
<insert id="" useGeneratedKeys="" keyProperty="">
insert into sys_user(
user_name, user_password,
<if test ="userEmail != null and userEmail !='' ">
  user_email,
</if>
user_info, head_img, create_time)
values(
#{userName}, #{userPassword},
<if test="userEmail != null and userEmail !='' ">
  #{userEmail},
</if>
#{userInfo}, #{headImg,jdbcType=BLOB},
#{createTime, jdbcType = TIMESTAMP})
</insert>


if标签提供了基本的条件判断,但是它无法实现if...else if...else...的逻辑,要想实现这样的逻辑,就需要用到choose when otherwise标签。choose元素中包含when和otherwise两个标签,一个choose中至少有一个when,有0个或者l个otherwise。

choose when when when 是if...else if...else if的关系,只会走其中的一条路,假如第一个when返回true,那么即使第二个第三个都为true,条件里也不会有第二个和第三个。
choose when 和下面的where 相比,没有剔除第一个条件前面的and或or的功能。
<select id= "" resultType="test.mybatis.simple.model.SysUser">
select id , user_name, user_password , user_email, user_info, head_img, create_time
from sys_user
where 1 = 1
<choose>
  <when test = "id != null">
    and id= #{id}
  </when>
  <when test= "userName != null and userName !='' ">
    and user_name = #{userName}
  </when>
  <otherwise>
    and 1 = 2
  </otherwise>
</choose>
</select>


where标签的作用:

1、当if条件都不满足的时候,where元素中没有内容,SQL中不会出现where;
2、紧跟在where元素后面的第一个查询条件前面如果以and 或 or开头,那么剔除;
3、where 标签,或where if 标签组合,没有给条件前面添加and 或 or 的功能,所以and或or一定要自己手动添加。


set标签的作用:

1、如果该标签包含的元素中有内容,就插入一个set,如果set元素中没有内容,不插入set标签,出现SQL错误,所以为了避免错误产生,类似id=#{id}这样必然存在的赋值仍然有保留的必要。从这一点来看,set标签并没有解决全部的问题,使用时仍然需要注意。
2、如果最后一个条件以逗号结尾,就将这个逗号剔除;其它条件的逗号不会加也不会减。


trim 标签

where和set标签的功能都可以用trim标签来实现,并且在底层就是通过TrimSqlNode实现的。
where标签对应trim的实现如下:
<trim prefix="WHERE" prefixOverrides="AND |OR " >
...
</trim>
这里的AND和OR后面的空格不能省略,为了避免匹配到andes、orders等单词。实际的prefixeOverrides 包含"AND"、"OR"、"AND\n"、"OR\n "、"AND\r"、"OR\r"、"AND\t"、"OR\t",不仅仅是上面提到的两个带空格的前缀。
set标签对应的trim实现如下。
<trim prefix="SET" suffixOverrides="," >
...
</trim>
trim 标签有如下属性。
prefix:当trim 元素内包含内容时,会给内容增加prefix 指定的前缀。
suffix:当trim 元素内包含内容时,会给内容增加suffix 指定的后缀。
prefixOverrides:当trim 元素内包含内容时,会把内容中匹配的前缀字符串去掉。
suffixOverrides:当trim 元素内包含内容时,会把内容中匹配的后缀字符串去掉。


foreach

foreach可以对数组、Map或实现了iterable接口(如List、Set)的对象进行遍历。数组在处理时会转换为List对象,因此foreach遍历的对象可以分为两大类:Iterable类型和Map类型。
collection:必填,值为要迭代循环的属性名。这个属性值的情况有很多。
item:变量名,值为从迭代对象中取出的每一个值,当迭代的对象是Map类型时,这个值为Map的value。
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代的对象是Map类型时,这个值为Map的key。
open:整个循环内容开头的字符串。
close:整个循环内容结尾的字符串。
separator:每次循环的分隔符。

collection的属性设置方法:
以下代码是DefaultSqlSession 中的方法,也是默认情况下的处理逻辑:
private Object wrapCollection(final Object object) {
  if (object instanceof Collection) {
    StrictMap<Object> map = new StrictMap<Object>();
    map.put("collection", object);
      if (object instanceof List) {
        map.put("list", object);
        return map;
      }
  } else if (object != null && object.getClass().isArray()) {
    StrictMap<Object> map = new StrictMap<Object>();
    map.put("array", object);
    return map;
  }
  return object;
}
当参数类型为集合的时候,默认会转换为Map 类型,并添加一个key 为"collection",如果参数类型是List 集合,那么就继续添加一个key 为"list",这样,当collection="list"时,就能得到这个集合,并对它进行循环操作。
当参数类型为数组的时候,也会转换成Map类型,默认的key为"array",使用数组参数时,就需要把foreach标签中的collection属性值设置为array。

List --> list 或者 collection
set --> collection
数组 --> array
map --> _parameter
推荐使用@Param 来指定参数的名字,这时collection 就设置为通过@Param 注解指定的名字。

SQL语句中有时会使用IN关键字,例如idin(1,2,3)。可以使用${ids}方式直接获取值,但这种写法不能防止SQL注入,想避免SQL注入就需要用#{}的方式,这时就要配合使用foreach标签来满足需求。
foreach 实现in 集合或数组
List<SysUser> selectByIdList(List<Long> idList);
<select id= "selectByIdList" resultType= "test.mybatis.simple.model.SysUser">
select id,user_name,user_password,user_email,user_Info,head_img,create_time
from sys_user
where id in
<foreach collection= "list" open="(" close=")" separator= "," item= "id" index = "index">
  #{id}
</foreach>
</select>

foreach 实现批量插入
如果数据库支持批量插入,就可以通过foreach 来实现。批量插入是SQL-92 新增的特性,目前支持的数据库有DB2, SQL Server 2008 及以上版本、PostgreSQL8.2及以上版本、MySQL、SQLite 3.7.11及以上版本、H2 。批量插入的语法如下。
INSERT INTO tablename (column-a, [column-b, ... ])
VALUES ('value-la', ['value-lb', ...]),
('value-2a', ['value-2b', ...]),
...
int insertList(List<SysUser> userList);
<insert id="insertList">
insert into sys_user(
  user_name , user_password, user_email, user_info, head_img, create_time)
values
<foreach collection ="list" item= "user" separator=",">
  (
    #{user.userName}, #{user.userPassword}, #{user.userEmail},
    #{user.userlnfo}, #{user.headlmg, jdbcType=BLOB} ,
    #{user.createTime, jdbcType=TIMESTAMP})
  )
</foreach>
</insert>
MyBatis支持批量新增回写主键值的功能(该功能由本书作者提交),这个功能首先要求数据库主键值为自增类型, 同时还要求该数据库提供的JDBC 驱动可以支持返回批量插入的主键值(JDBC 提供了接口,但并不是所有数据库都完美实现了该接口),因此到目前为止,可以完美支持该功能的仅有MySQL 数据库。由于SQLServer 数据库
官方提供的JDBC只能返回最后一个插入数据的主键值,所以不能支持该功能。如果要在MySQL 中实现批量插入返回自增主键值, 只需要在原来代码基础上进行如下修改即可。注意,mybatis版本要是3.3.1或以上。
<insert id= "insertList" useGeneratedKeys ="true" keyProperty="id">

foreach 实现动态UPDATE
int updateByMap(Map<String, Object> map);
<update id="">
  update sys_user
set
<foreach collection="_parameter" item="val" index="key" separator=",">
  ${key} = #{val}
</foreach>
where id = #{id}
</update>

mybatis 的动态SQL的更多相关文章

  1. MyBatis的动态SQL详解

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它 ...

  2. Mybatis解析动态sql原理分析

    前言 废话不多说,直接进入文章. 我们在使用mybatis的时候,会在xml中编写sql语句. 比如这段动态sql代码: <update id="update" parame ...

  3. mybatis 使用动态SQL

    RoleMapper.java public interface RoleMapper { public void add(Role role); public void update(Role ro ...

  4. MyBatis框架——动态SQL、缓存机制、逆向工程

    MyBatis框架--动态SQL.缓存机制.逆向工程 一.Dynamic SQL 为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句.最常用的就是:where和if标签 1.参考 ...

  5. 使用Mybatis实现动态SQL(一)

    使用Mybatis实现动态SQL 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 写在前面:        *本章节适合有Mybatis基础者观看* 前置讲解 我现在写一个查询全部的 ...

  6. MyBatis探究-----动态SQL详解

    1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不 ...

  7. mybatis中的.xml文件总结——mybatis的动态sql

    resultMap resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功. 如果sql查询字段名和pojo的属性名不一致,可以通过re ...

  8. mybatis.5.动态SQL

    1.动态SQL,解决关联sql字符串的问题,mybatis的动态sql基于OGNL表达式 if语句,在DeptMapper.xml增加如下语句; <select id="selectB ...

  9. MyBatis的动态SQL详解-各种标签使用

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  10. 利用MyBatis的动态SQL特性抽象统一SQL查询接口

    1. SQL查询的统一抽象 MyBatis制动动态SQL的构造,利用动态SQL和自定义的参数Bean抽象,可以将绝大部分SQL查询抽象为一个统一接口,查询参数使用一个自定义bean继承Map,使用映射 ...

随机推荐

  1. Window - 浏览器对象模型

    浏览器对象模型 (BOM) 浏览器对象模型(Browser Object Model (BOM))尚无正式标准. 由于现代浏览器已经(几乎)实现了 JavaScript 交互性方面的相同方法和属性,因 ...

  2. Matlab 基础

    命令行(Command Line) 1. help  格式:help  命令 2. cd 配合 Tab 使用 pwd: print current working directory,打印当前工作路径 ...

  3. (转) Linux(Centos7)yum安装最新mysql

    原文:http://blog.csdn.net/gebitan505/article/details/54613549 环境 CentOS 7.1 (64-bit system) MySQL 5.6. ...

  4. Java之集合(十四)Hashtable

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7426522.html 1.前言 HashTable这个类很奇特,其继承了Dictionary这个没有任何具体实现 ...

  5. django第一课 简单的网页视图

    注意本人django版本2.0      python3.6 第一步:创建自己的django项目 django-admin.py startproject ** 第二步:进入**创建app pytho ...

  6. Java8-Guava实战示例

      示例一: 跟示例三对比一下,尽量用示例三 List<InvoiceQueryBean> invoiceQueryBeanList = new ArrayList<>(); ...

  7. RocketMQ-Filer

    一.搭建RocketMQ集群 我搭建的是2-master no slave模式,所以在${rocketmq}/conf/2m-noslave/下的 brokder-*.properties 中添加 f ...

  8. Sklearn-RandomForest

    在scikit-learn中,RandomForest的分类类是RandomForestClassifier,回归类是RandomForestRegressor,需要调参的参数包括两部分,第一部分是B ...

  9. GBDT多分类示例

    相当于每次都是用2分类,然后不停的训练,最后把所有的弱分类器来进行汇总 样本编号 花萼长度(cm) 花萼宽度(cm) 花瓣长度(cm) 花瓣宽度 花的种类 1 5.1 3.5 1.4 0.2 山鸢尾 ...

  10. JDK动态代理[2]----JDK动态代理的底层实现之Proxy源码分析

    在上一篇里为大家简单介绍了什么是代理模式?为什么要使用代理模式?并用例子演示了一下静态代理和动态代理的实现,分析了静态代理和动态代理各自的优缺点.在这一篇中笔者打算深入源码为大家剖析JDK动态代理实现 ...