MyBatis动态sql

if

if 标签通常用于 WHE阻 语句中,通过判断参数值来决定是否使用某个查询条件,它也经常用于 UPDATE 语句中判断是否更新某一个字段 , 还可以在 INSERT 语句中用来判断是否插入某个字段的值。

if 标签有一个必填的属性 test, test 的属性值是一个符合 OGNL 要求的判断表达式,表达式的结果可以是 true 或 false ,除此之外所有的非 0值都为 true ,只有0为 false 。 为了方便理解,在表达式中 ,建议只用 true 或 false 作为结果 。

  • 判断条件 property ! =nu ll 或 property == null : 适用于任何类型的宇段 ,用于判断属性值是否为空。
  • 判断条件 property != '' 或 prope rty == '': 仅适用于 String 类型的宇段 ,用于判断是否为空字符串 。
  • and 和 or :当有多个判断条件时,使用 and 或 or 进行连接,嵌套的判断可以使用小括号分组, and 相当于
    Java 中的与(&&), or 相当于 Java 中的或 (||)。
    上面两个条件的属性类型都是 String,对字符串的判断和 Java 中的判断类似,首先需要判断字段是否为 null ,然后再去判断是否为空(在 OGNL 表达式中 ,这两个判断的顺序不会影响判断的结果,也不会有空指针异常)。在本章所有例子中,字符串的判断几乎都包含 null和空的判断,这两个条件不是必须写在一起,可以根据实际业务决定是否需要空值判断 。

choose when otherwise

if 标签提供了基本的条件判断,但是它无法实现 if. . . else 、 if ... else ...的逻辑,要想实现这样的逻辑,就需用到 choose when otherwise 标签。
choose 元素中包含 when和 otherwise 两个标签,一个 choose 中至少有一个 when ,有 0 个或者1 个
otherwise 。在己有的 sys_user 表中,除了主键 id 外,我们认为 user_name (用户名)也是唯一的,所有的用户名都不可以重复 。 现在进行如下查询:
当参数 id 有值的时候优先使用 id 查询,当 id 没有值时就去判断用户名是否有值,如果有值就用用户名查询 ,如果用 户名也没有值,就使 SQL 查询无结果 。

<select id=” selectByidOrUserName” resultType=” tk.mybatis.simple.m0del. SysUser” >
  select id,
    user_name,
    user_password,
    user_email,
    user_info
  from sys_ user
  where 1 = 1
  <choose >
    <when test=” id != null ” >
        and id= #{id}
    </when >
    <when test=” u serName != null and userName !=””>
      and user name = #{userName}
    </when>
    <otherwise>
      and 1 = 2
    </otherwise>
  </choose>
</ select>

在以上查询中,如果没有 otherwise 这个限制条件,所有的用户都会被查询出来,因为
我们在对应 的接口方法中使用了 Sys User 作为返回值,所以当实际查询结果是多个时就会报
错。 添加 otherwise 条件后,由于 where 条件不满足,因此在这种情况下就查询不到结果。

where

这 3 个标签解决了类似的问题,并且 where 和 set 都属于 trim 的一种具体用法。下面分别来看这 3 个标签。
where 标签的作用:如果该标签包含的元素中有返回值,就插入一个 where ;如果 where后面的字符串是以 AND 和 OR 开头的,就将它们剔除。

<select id=” selectByUser” resultType=” tk . mybatis . simple . model . SysUser” >
*
from sys_user
<where>
  <if test=”userName != null and userName !=””>
    and user_name like concat ( ’ %’,#{userName} , ’ % ’)
  </ if>
  <if test=”userEmail ! = ” and userEmail != null ”>
    and user email = #{userEmail}
  </ if>
</where>
</select >

当 if 条件都不满足的时候, where 元素中没有内容,所以在 SQL 中不会出现 where , 如果 if 条件满足, where 元素的内容就是以 and 开头的条件, where 会自动去掉开头的 and,这也能保证 where 条件正确 。这种情况下生成的 SQL 更干净、更贴切,不会在任何情况下都有 where 1 = 1 这样的条件 。

set

set 标签的作用:如果该标签包含的元素中有返回值,就插入一个 set :如果 set 后面的字符串是 以逗号结尾的,就将这个逗号剔除 。

<update id=”updateByidSelective ” >
    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>
        <i f test=” userinfo != null and userinfo !=””>
            user info = #{userinfo},
        </if>
        <if test=”headimg != null ” >
            head_img = #{headimg, jdbcType=BLOB},
        </if >
        <if test=”createTime != nul l ”>
            create_time = #{createTime, jdbcType=TIMESTAMP},
        </if>
    id = # {id} ,
    </set>
    where id = #{id}
</ update>

在 set 标签的用法中 , SQL 后面的逗号没有问题了,但是如果 set 元素中没有内容,照样
会出现 SQL 错误,所以为了避免错误产生,类似 id = #{id }这样必然存在的赋值仍然有保留
的必要。从这一点来看, set 标签并没有解决全部的问题,使用时仍然需要注意。

trim

where 和 set 标签 的功能都可以用 trim 标签来实现,并且在底层就是通过TrimSqlNode 实现的 。
where 标签对应 trim 的实现如下。

<trim prefix=”WHERE ” prefixOverrides=”AND IOR ” >
    ......
</ 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” suf f ixOverrides=”, ” >
  .....
</ trim>

trim 标签有如下属性。
prefix :当 trim 元素内包含内容时,会给内容增加 prefix 指定的前缀。
prefixOverrides :当 trim 元素内包含内容时,会把内容中匹配的前缀字符串去掉。
suffix :当 trim 元素内包含内容时,会给内容增加 suffix 指定的后缀。
suffixOverrides :当 trim 元素内包含内容时,会把内容中匹配的后缀字符串去掉。

foreach

SQL 语句中有时会使用 IN 关键字,例如 id in ( 1 , 2 , 3 )。可以使用${ids}方式直接获取值,但这种写法不能防止 SQL 注入,想避免 SQL 注入就需要用#{}的方式,这时就要配合使用 foreach 标签来满足需求。
foreach 可以对数组、 Map 或实现了工 terable 接口(如 List 、 Set )的对象进行遍历。数组在处理时会转换为 List 对象,因此 foreach 遍历的对象可以分为两大类 : Iterable类型和 Map 类型

foreach 实现 in 集合(或数组)是最简单和常用的一种情况
<foreach collection=” lis t ” open=” (” close=” )” separator=” , ” item=” id” index=” i ” >
    #{id}
</foreach>

foreach 包含以下属性。

  • collection : 必填,值为要选代循环的属性名。这个属性值的情况有很多。
  • item:变量名,值为从法代对象中取出的每一个值。
  • index :索引的属性名,在集合数组情况下值为当前索引值 ,当选代循环的对象是 Map类型时,这个值为 Map 的 key (键值)。
  • open:整个循环内容开头的字符串 。
  • close : 整个循环内容结尾的字符串。
  • separator :每次循环的分隔符 。

bind

bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中。在前面的例子中,UserMapper.xml 有一个 selectByUser 方法,这个方法用到了 like 查询条件,部分代码如下 。

<if test=” userNarne != null and userNarne ! = ””>
    and user name like concat ( ’ % ’, #{ userNarne },’ % ’ )
</if>

使用 con cat 函数连接字符串,在 MySQL 中,这个函数支持多个参数,但在 Oracle 中只支持两个参数。由于不 同数据库之间的语法差异 ,如果更换数据库,有些 SQL 语句可能就需要重写。针对这种情况,可 以使用 bind 标签来避免由于更换数据库带来的一些麻烦。将上面的
方法改为 bind 方式后,代码如下。

<if test=” userNarne != null and userNarne !=””>
    <bind narne= " userNarneLike ” value = '%'+ userNarne + '%'/>
    and user name like #{userNarneLike}
</if>

bind 标签的两个属性都是必选项, name 为绑定到上下文的变量名, value 为 OGNL 表
达式。创建一个 bind 标签的变量后 ,就可以在下面直接使用,使用 bind 拼接字符串不仅可
以避免因更换数据库而修改 SQL,也能预防 SQL 注入。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • MyBatis 动态SQL 内容 Mybatis动态SQL在XML中支持的几种标签: if chose trim、...
    lihongyan阅读 8,339评论 1 10
  • 在讲MyBatis动态SQL之前,先教大家怎么通过MyBatis插件自动生成mapper对应的文件和对应的b...
    tuacy阅读 1,602评论 0 23
  • Mybatis的强大特性之一便是它的动态SQL。在实际开发中,数据库的查询比较复杂,需要在不同的逻辑中执行不同的S...
    Michaelhbjian阅读 4,155评论 0 2
  • Mybatis学习 mybatis http://www.mybatis.org/mybatis-3/zh/ind...
    墙上藤蔓阅读 751评论 3 2
  • 、 、 、 :trim标签主要就是标记的作用,可以去掉if条件不满足时多余的and或者or或者,等等,和set标...
    小沙鹰168阅读 1,963评论 0 0