MyBatis 动态SQL 标签 常用OGNL表达式 内置参数 if choose (when, otherwise) trim (where, set) foreach script bind 分表demo

  1. if
  2. choose (when, otherwise)
  3. trim (where, set)
  4. foreach

常用OGNL表达式

e1 or e2
e1 and e2
e1 == e2,e1 eq e2
e1 != e2,e1 neq e2
e1 lt e2:小于
e1 lte e2:小于等于,其他gt(大于),gte(大于等于)
e1 in e2
e1 not in e2
e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e2
!e,not e:非,求反
e.method(args)调用对象方法
e.property对象属性值
e1[ e2 ]按索引取值,List,数组和Map
@class@method(args)调用类的静态方法
@class@field调用类的静态字段值

内置参数

_parameter是传到SQL语句中的Java对象的参数,如果有一个则是直接取得,如果有多个则可以通过get(0)这样的方法取得每一个。
配置了databaseIdProvider的配置文件可以通过_databaseId 变量获取数据库类型

if

可以在SQL语句标签中插入形如

  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>

的if标签,MyBatis会对test属性中的语句进行逻辑判断,test语句支持逻辑判断和逻辑运算符,或者说支持OGNL表达式。
当test结果为真时,if标签中包括的内容就会添加到SQL语句中。

choose (when, otherwise)

choose标签是一个多选一的标签,就像Java中的switch,当匹配到when子标签中的内容时,就会将when中的SQL语句拼接起来,如果没有匹配就会将otherwise中的语句拼接起来。

  <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>

trim (where, set)

where中可以嵌套多个if之类的子元素,将满足条件的子元素拼接成SQL语句中WHERE子句的一部分。
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

set与where类似,可以将子元素中满足test条件的语句拼接起来,设置为update的SET子句,还可以去掉拼接起来的语句最后的逗号。

trim

trim可以做到where和set的功能,如下所示就是WHERE的实现:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性会忽略通过管道分隔的文本序列,上面代码的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。
如下是SET的实现:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

可见,trim标签的属性可以使用prefix属性在拼接的语句前面增加某个关键字,使用suffixOverrides去掉最后的某些输入。

foreach

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

<select >
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

foreach的功能显而易见,当使用可迭代对象时,item是游标,index是当前项,而当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

script

要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

    @Update({"<script>",
      "update Author",
      "  <set>",
      "    <if test='username != null'>username=#{username},</if>",
      "    <if test='password != null'>password=#{password},</if>",
      "    <if test='email != null'>email=#{email},</if>",
      "    <if test='bio != null'>bio=#{bio}</if>",
      "  </set>",
      "where id=#{id}",
      "</script>"})
    void updateAuthorValues(Author author);

bind

bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

<select >
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

分表demo

//Java实体类继承次接口则允许分表
public interface IDynamicTableName {

    /**
     * 获取动态表名 - 只要有返回值,不是null和'',就会用返回值作为表名
     *
     * @return
     */
    String getDynamicTableName();
}

通过OGNL表达式调用静态方法,对是否能分表进行判断

<if test="@tk.mybatis.mapper.util.OGNL@isDynamicParameter(_parameter) 
            and dynamicTableName != null 
            and dynamicTableName != ''">
    ${dynamicTableName}<!--MyBatis通过get方法从实体对象中取值,因此会调用上面接口定义的方法获取动态表名-->
</if>
<if test="@tk.mybatis.mapper.util.OGNL@isNotDynamicParameter(_parameter) 
            or dynamicTableName == null 
            or dynamicTableName == ''">
    defaultTableName
</if>

是否能分表的静态方法定义:

/**
 * 判断参数是否支持动态表名
 *
 * @param parameter
 * @return true支持,false不支持
 */
public static boolean isDynamicParameter(Object parameter) {
    if (parameter != null && parameter instanceof IDynamicTableName) {
        return true;
    }
    return false;
}

/**
 * 判断参数是否支持动态表名
 *
 * @param parameter
 * @return true不支持,false支持
 */
public static boolean isNotDynamicParameter(Object parameter) {
    return !isDynamicParameter(parameter);
}