• mybatis 的动态SQL


    在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 "、"OR "、"AND "、"OR "、"AND "、"OR ",不仅仅是上面提到的两个带空格的前缀。
    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>

  • 相关阅读:
    MySQL 5.1.73升级为MySQL 5.5.35详解
    MySQL 常用show命令
    MySQL 用户与授权管理详解
    MySQL 日志管理详解
    MySQL 5.5.35 单机多实例配置详解
    mysql启动与关闭(手动与自动)
    hduTHE MATRIX PROBLEM(差分约束)
    在 iPad和 iPhone的浏览器上查看网页源代码
    《30天自制操作系统》之——第3天
    python network programming tutorial
  • 原文地址:https://www.cnblogs.com/Mike_Chang/p/9348961.html
Copyright © 2020-2023  润新知