MyBatis动态sql

MyBatis 的强大特性之 便是它的动态 SQL 。使用过 JDB 或其他类似框架的人都会知道,根据不同条件拼接 SQL 语句时不仅不能忘了必要的空格,还要注意省略掉列名列表最后的逗号,处理方式麻烦且凌乱。 MyBatis 的动态 SQL 则能让我们摆脱这种痛苦。MyBatis 之前的版本中,使用动态 SQL 需要学习和了解非常多的标签,现在MyBatis采用了功能强大的 OGNL ( Object-Graph Navigation Language )表达式语言消除了许多其他标签,
以下是 MyBatis 的动态 SQL XML 中支持的几种标签

• if
• choose (when,oterwise)
• trim (where、set)
• foreach
• bind

本章除了讲解这几种标签的用法外,还会介绍如何在 XM 中针对不同的数据库编写不同的 SQL 语句,另外会对这 5种标签中必须要用到的OGNL 表达式进行一个简单的介绍

1、if 用法

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

1.1、WHERE 条件中使用 if

假设现在有一个新的需求实现一个用户管理高级查询功能,根据输入的条件去检索用户信息。这个功能还需要支持以下三种情况 当只输入用户名时,需要根据用户名进行模糊查询:当只输入邮箱时,根据邮箱进行完全匹配:当同时输入用户名和邮箱时,用这两个条件去查询匹配的用户。

如果仍然按照前面章节中介绍的方法去编写代码,可能会写出如下方法

<select id=” selectByUser” result Type=” t k.mybatis.s mple.model.SysUser>
select id,
user name userName ,
user password userPassword ,
user email userEmail ,
user info userinfo ,
head img headimg ,
create time createTime
from sys_user
where user_name like concat(‘%’,#{userName} ,’%’)
and user_email = # {userEmail}
</select >

当同时输入 userName user Ema 这两个条件时,能查出正确的结果,但是当只提供userName 参数值时, serE mail 默认是null,这就会导致 user email =null 也成
为查询条件 ,因而查不 正确的结果。这时就可以使用 if 标签来解决这个问题了,代码如下

<select id=”selectByUser” resultType=”tk.mybatis.simple.model.SysUser” >
select id,
user name userName ,
user password userPassword,
user email userEma
use fo userinfo ,
head img headimg ,
create me createTime
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>

if 标签有 个必填的属性 test, test 的属性值是一个符合 OGNL 要求的判断表达式,表达式的结果可以是 true,false ,除此之外所有的非0值都为 true ,只有0为 false,方便理解,在表达式中 ,建议只用 true false 作为结果 OGNL 的详细用法在 4.7 节中会有比较完整的介绍,这里暂且只关注 以下内容

判断条件 property !=nu ll或property == null 适用于任何类型的宇段 ,用于判断属性值是否为空。
判断条件 property!=“”或 property==“”: 仅适用于 String 类型的宇段用于判断是否为空字符串
• and or 当有多个判断条件时,使用 and or 进行连接,嵌套的判断可以使用小

括号分组, and 相当于 Java 中的与(&&), or 相当于 Java 中的或 (||)。
上面两个条件的属性类型都是 String ,对字符串的判断和 Java 中的判断类似,首先需要判断字段是否为 null ,然后再去判断是否为空(在 OGNL 表达式中 ,这两个判断的顺序不会影响判断的结果,也不会有空指针异常)。在本章所有例子中,字符串的判断几乎都包含 null和空的判断,这两个条件不是必须写在一起,可以根据实际业务决定是否需要空值判断

有了 XML 中的方法后,还需要在 UserMapper 接口中增加对应的接口方法,代码如下。

List<SysUser> selectByUser(SysUser sysUser);

虽然实现了需求,但是在 XML 的方法中仍然有两个地方需要注意
• 注意 SQL 中where 关键字后面的条件
where 1 = 1
由于两个条件都是动态的,所以如果没有where 1=1 这个默认条件,当两个 if 判断都不满足时
最后生成 SQL 就会以 where 结束,这样不符合 SQL 规范,因此会报错。加上 1=1 这个条件
就可以避免 SQL 语法错误导致的异常 这种写法并不美观,在 4.3 节中会介绍 where 标签的
用法,可 以替代这种写法
. 注意条件中的 and (或 or)
and user name like concat (’ ’,#{ userName },
这里 and (或 or )需要手动添加,当这部分条件拼接到 where 1 = 后面时仍然是合
法的 SQL 。因 为有默认的 1=1 这个条件,我们才不需要判断第一个动态条件是否需要加上 and
(或 or ,因为这种情况下 and (或 or )是必须有的。

1.2、UPDATE 更新列中使用 if

现在要实现这样一个需求:只更新有变化的字段。需要注意,更新的时候不能将原来有值
但没有发生变化的字段更新为空或null。通过 if 标签可以实现这种动态列更新

一般情况下 MyBatis 中选择性更新的方法名会以 Selective 作为后缀。

接下来在 UserMapper.xml 中添加对应的 SQL 语句,代码如下

<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>
test=”userlnfo != null and userlnfo ! = ””>
user_info= #{userlnfo},
</if>
<if test=” headlmg != nul l ”>
head_img = #{headlmg, jdbcType=BLOB},
</if>
<if test createTime != null ”>
create_time = #{createTime, jdbcType=TIMESTAMP},
</if>
id = #{id}
where id = #{id}
</update>

这里要结合业务层的逻辑判断,确保最终产生 SQL 吾句没有语法错误。需要注意的有两点:第 点是每个 if 元素里面 SQL 语句后面的逗号 第二点就是 where 关键宇前面的 id=#{id }这个条件。以下两种情况可以帮助大家理解为什么需要关注这两点。

• 全部的查询条件都是 null 或者空。如果有 id = #{id }这个条件,最终的 SQL 如下。
update sys user set id= #{id} where id= #{id}
如果没有这个条件,最终的 SQL 如下
update sys user set where id = #{id}

这个 SQL 很明 显是错误的,set 关键字后面没有内容,直接是 where 关键宇,不符合 SQL语句规范

• 查询条件只有一个不是 null 也不是空(假设是 userName
如果有 id = #{id }这个条件,最终的 SQL 如下。
update sys user set user name= #{userName} , id = #{id} where id= #{id}
如果没有这个条件,最终的 SQL 如下
update sys user set user name= # {userName}, where id= #{id}
where 关键宇前面直接是 个逗号,这个 sQL 语句 是错的。

从上面两种情况来看, id = #{id }这个条件可以最大限度保证方法不出错。除了使用这
种方式外,还可以结合业务层的逻辑判断调整 XML 文件中的 SQL 来确保最终的 SQL 语句的正
确性,也可以通过 where set 标签来解决这些 问题。

1.3、INSERT 动态插入列中使用 if

在数据库表中插入数据的时候,如果某 列的参数值不为空,就使用传入的值,如果传入参数为空,就使用数据库中的默认值(通常是空),而不使用传入的空值 使用 if 就可以这种动态插入列的功能。

先修改 sys_user 表,在数据库中执行如下的 SQL 语句给 user_email 列增加默认值
test@mybat .tk

下面直接修改 SysUserMapper.xm 中的 insert2 方法。

<insert id=”insert2 ” useGeneratedKeys=” true“ 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,]dbcType=BLOB} ,
#{createTime, jdbcType= TIMESTAMP})
</insert>

INSERT中使用时要注意,若在列的部分增加 if 条件,则 values 的部分也要增加相同的 if 条件,必须保证上下可以互相对应,完全匹配。

2、choose 用法

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

然后在 serMapper.xml 中添加如下 SQL

<select id=”selectByidOrUserName” resultType=” tk.mybatis.simple.m0del. SysUser” >
select id,
user name userName ,
us e r password userPassword,
user email userEmail ,
user info userinfo ,
head_img headimg ,
create time createTime
from sys_ user
where 1 = 1
<choose>
<when test=” id != nul l ” >
and id= #{id}
</when>
<when test=”userName != null and userName !=''”>
and user_name = #{userName}
</when>
<otherwise>
and 1 = 2
</otherwise>
</ choose>
</select>

使用 choose when otherwis 的时候逻辑要严密,避免由于某些值出现问题导致 SQL出错

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

3、where、set、 trim 用法

3个标签解决了类似的问题,并且 where set 都属于 trim 的一种具体用法。下面
分别来看这3个标签。

3.1、where 用法

where 标签的作用:如果该标签包含的元素中有返回值,就插入 where ;如果 where后面字符串是以 AND OR 开头的,就将它们剔除。首先修 serMapper.xml 中的 selectByUser 方法,注意这个方法在 1.1 节中的用法此处将这个方法改成使用 where 标签,代码如下。

<select id=” selectByUser” result Type=” tk . mybatis . simple . model . SysUser” >
select id,
user name u serName,
u ser password userPassword,
user ema 工 l userEmail ,
u ser info userinfo ,
head img headimg,
create time createTime
from sys user
<where>
<if test=”userName != null and userName !=””>
and user name ke concat ’,#{ serName ’)
</ if>
<if test=” userEmail != ” and userEmail != nul l ”>
and user email = #{userEmail}
</ if>
</where>
</select >

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

3.2、set用法

set 标签的作用:如果该标签包含的元素中有返回值,就插入 set :如果 set 后面的字符串是 以逗号结尾的,就将这个逗号剔除修改 serMap er ml 中的 updateByidSelective 方法,注意和 1.2 节中的 区别,代码如下。

<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>
<if 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 标签并没有解决全部的问题,使用时仍然需要注意。

3.3、trim 用法

where、set 标签 的功能都可以用 trim 标签来实现,并且在底层就是通过TrimSqlNode 实现的

where 标签对应 trim 的实现如下。<trim prefix=”WHERE ” prefixOverrides=”AND IOR ” ></trim>

这里的 AND OR 后面的空格不能省略,为了避免匹配到 an des orders 等单词实际的 prefixeOverrides 包含“AND”、“ OR”、“AND\n ”、“ OR\n ”、“ AND\r ”、飞R\r ”、AND\t ”、 OR \t ”, 不仅仅是上面提到的两个带空格的前缀

set 标签对应 trim 实现如下<trim prefix=” SET” suffixOverrides=”, ” ></ trim>

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

3.4、foreach 用法

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

foreach 可以对数组、 Map 或实现了工terable 接口(如 List Set )的对象进行遍
历。数组在处理时会转换为 List 对象,因此 foreach 遍历的对象可以分为两大类 Iterable
类型和 Map 类型。这两种类型在遍历循环时情况不一样,这一节会通过 个例子来讲解
foreach 的用法。

3.4.1、foreach 实现 in 集合

foreach 实现 in 集合(或数组)是最简单和常用的 种情况,下面介绍如何根据传入的用户 id 集合查询出所有符合条件的用户。

UserMpper.xml 中增加如下代码

<select id=” selectByidList” resultType=” tk .mybatis . simple .model . SysUser” >select id, user name userName , user password userPassword, user email userEmail, use fo userinfo , head img headimg, create time createTime from sys_user where id in <foreach collection=”list ” open=” (” close=” )” separator=” , ” item=” id” index=” i ” >#{id}</foreach> </ select>

foreach 包含以下属性。
collection 必填,值为要选代循环的属性名。这个属性值的情况有很多。
• item :变量名,值为从法代对象中取出的每一个值。
index :索引的属性名,在集合数组情况下值为当前索引值 当选代循环的对象是 Map
类型时,这个值为 Map key (键值)。
ope 口:整个循环内容开头的字符串
close 整个循环内容结尾的字符串。
separator :每次循环的分隔符
collect io口的属性要如何设置呢?来看一下 MyBatis 是如何处理这种类型的参数的。

只有一个数组参数或集合参数
以下代码是 DefaultSqlSession 中的方法, 是默认情况下的 理逻辑

private Object wrapCollection(final Object object) { if (object instanceof Collection) { StrictMap<Object> map = new StrictMap<Object> () ; map put collect on ”, object)if (object instanceof List) { map . put (” list", object) ; return map; } else if (object != null 品品 object . getClass() . isArray()) { StrictMap<Object> map =口ew StrictMap<Object>() ; map.put (” array”, object) ; return map; return ob] ect;

当参数类型为集合的时候,默认会转换为 Map 类型,井添加 key collection
值( MyBatis 3.3 版本中增加),如果参数类型是 List 集合,那么就继续添加 key list
的值( MyBatis 3.2.8 及低版本中只有这 key ),这样,当 collection=" list ”时, 就能得
到这个集合,并对它进行循环操作。
当参数类型为数组的时候,也会转换成 Map 类型,默认的 key array 。当采用如下方法使用数组参数时,就需要把 foreach 标签中的 collection 属性值设置为 array

  1. 有多个参数
    章中讲过 当有多个参数的时候,要使用@ Par am 注解给每个参数指定 个名字, 否则
    SQL 中使用参数时就会不方便,因此将 collection 设置为@ Param 注解指定的名字即可
  2. 参数是 Map 类型
    使用 Map 和使用@ Par am 注解方式类似,将 collection 指定为对应 Map 中的 key 即可
    如果要循环所传入的 Map ,推荐使用@ Par am 注解指定名字,此时可将 collection 置为指
    定的名字,如果不想指定名字 ,就使用默认值 parameter
  3. 参数是一个对象
    这种情况下指定为对象的属性名即可。当使用对象内多层嵌套的对象时,使用属性.属性(集
    合和数组可以使用下标取值)的方式可以指定深层的属性值。

可以 察日志打 印的 SQL 语句, foreach 元素中的内容最终成为了 口(? ?),根
据这部分 内容很容易就能理解 ope item separat lose 这些属性的作用
关于不 同集合类型参数的相 内容,建议大家利用上面的基础方法多去尝试,帮助更好地

3.4.2、foreach 实现批量插入

如果数据库支持批量插入,就可以通过 foreach 来实现。 插入是 SQL-92 新增的特性,
目前支持的数据库有 DB2, SQL Sever 2008 及以上版本、 PostgreSQL 及以上版本、 MySQL
SQLite 3.7. 1 及以上版本、 H2 。批量插入的语法如下。
INSERT INTO tablename (column- a , [column-b,

从待处理部分可以看出,后面是一个值的循环,因此可以通过 foreach 实现循环插入。

UserMapper xml 添加如下 SQL

<insert id=”insertList”>insert into sys_user( user ame user password, user email , user_info , head_img , create_time) values <foreach collection=” list ” i tern=” user” separator=”,”>#{user.userName}, #{user . userPassword},#{user . userEmail} , #{user.userlnfo} , #{user.headlmg, jdbcType=BLOB} , #{user.createTime , jdbcType=TIMESTAMP}) </foreach> </insert>

通过 item 指定了循环变量名后,在引用值的时候使用的是“属性.属性”的方式,如user.userName

My ti 3.3. 版本开始 MyBati 开始支持批量新增回写主键值 功能(该功能由本书作者提交) 这个功能首先要求数据库主键值为自增类型, 同时还要求该数据库提供 JDBC动可以支持返回批量插入的主键值 JDBC 提供了接口 但并不是所有数据库都完美实现了该接口),因此到目前为止 可以完美支持该功能的仅有 MySQL 数据库。由于 SQLrver 数据库官方提供的 JDB 只能返回最后 个插入数据的主键值,所 不能支持该功能。如果要在 SQ 中实现批量插入返回自增主键值 只需要在原来 码基 上进行如下修改即可。

<insert id=” insertList” useGeneratedKeys=” true ” keyProperty=” id” >和单表 样,此处增加了useGeneratedKeys eyProperty 性, 这两个属性后,简单修改测试类,输出 id 值。

关于批量插入的内容就介绍这么多,对于不支持该功能的数据库,许多人会通过select … ion all select …的方式去实现,这种方式在不同数据库中实现也不同,并且这种实现也不安全,因此本书中不再提供示例。

3.4.3、foreach 实现动态 UPDATE

foreach 实现动态 UPDATE节主要介绍当参数类型是 Map 时, foreach 如何实现动态 UPDAT
当参数是 Map 类型的时候, foreach 标签的index 属性值对应的不是索引值,而是 Map中的 key ,利用这个 key 可以实现动态 UPDATE现在需要通过指定的列名和对应的值去更新数据,实现代码如下

update MM set <foreach collection= ” __parameter” i tern=” val ” i ndex=” key” separator=”,”>${key} = #{val} </foreach> where id = #{id} </update>

3.5、bind 用法

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

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

使用 con cat 函数连接字符串,在 yS QL 中,这个函数支持多个参数,但在 Oracle 中只
支持两个参数。由于不 同数据库之间的语法差异 ,如果更换数据库,有些 SQL 语句可能就需要
重写。针对这种情况,可 以使用 bind 标签来避免由于更换数据库带来的一些麻烦。将上面的
方法改为 bind 方式后,代码如下。
<if test=” userNarne != null and userNarne !=””>
<bind narne= userNarneLike value ”’ ’+ userNarne ’”
and user name like #{userNarneLike}

bind 标签的两个属性都是必选项, name 为绑定到上下文的变量名, value OGNL表
达式。创建一个 bind 标签的变量后 就可以在下面直接使用,使用 bind 拼接字符串不仅可
以避免因更换数据库而修改 QL ,也能预防 SQL 注入。大家可以根据需求,灵活使用 OGNL
表达式来实现功能 关于更多常用的 OGNL 表达式,我们会在 4.7 节中详细介绍。

3.6、多数据库支持

bind 标签并不能解决更换数据库带来的所有问题,那么还可以通过什么方式支持不同的数据库呢?这需要用到 if 标签以及由 MyBati 提供的 databaseidProvider 数据库厂商标识配置。

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseld 属性的。 MyBatis 会加载不带 database Id 属性和带有匹配当前数据库databaseld 属性的所有语句。如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseidProvider 配置即可。

<databaseidProvider type=” DB_VENDOR” />

这里的 DB_VENDOR 会通过 DatabaseMetaData#getDatabaseProductName ()返回的字符串进行设置。由于通常情况下这个字符串都非常长而且相同产品的不同版本会返回不同的值,所以通常会通过设置属性别名来使其变短,代码如下。

<databaseidProvider type=”DB_VENDOR” > <property name=” SQL Server ” value=” sqlserver” /><property name=” DB2 ” value=” db2 ” /><property name=” Oracle ” value=” oracle ” /><property name=”MySQL ” value=”rnysql”/><property name=” PostgreSQL” value=” p ostgresql ” /><property name=” Derby ” value=” derby " /> <property name=” HSQL ” value=” h sqldb” /><property name H2 value h2 /〉</data:baseidProvider>

上面列举了常见的数据库产品名称,在有 property 配置时, databaseid 将被设置为第个能匹配数据库产品名称的属性键对应的值, 如果没有匹配的属性则会被设置为 null 。在这个例子中,如果 getDatabaseProductName ()返回 Microsoft SQL Server, databaseid 将被设置为 sqlserver

DB VENDOR 匹配策略为, Datab ase MetaData#getDatabaseProductName ()返
回的字符串包含 property name 部分的值即可匹配,所以虽然 SQL Server 的产品全名一
般为 icrosoft SQL Server 但这里只要设直为 SQL Server 就可以匹配
数据库产 品名一般由所选择的当前数据库的 JDBC 驱动所决定,只要找到对应数据库
DatabaseMetaData 口的实现类,一般在 getDatabaseProductName ()方法中就可以直接
找到该值 任何情况下都可以通过调用 DatabaseMetaData#getDatabaseProductName ()方
法获取具体的值

除了增加上面的配置外,映射文件也是要变化的, 关键在于 以下几个映射文件的标签中含
有的 database Id 属性

• select
• insert
• delete
• update
• selectKey
• sql
个简单例子来介绍 database Id 属性如何使用。针对 MySQL Oracle 数据库提供下面两个不同版本的 like 查询方法。

<select id=” selectByUser” database Id=” mysql ”
result Type=” tk .mybatis . simple.model.SysUser” >
select* from sys_userand where user_name like concat (' ’,# userName },’ ’)

<se lect id=” selectByUser” database Id=” oracle ”
result Type=” t k.mybatis. simple.model.SysUser” >
select * from sys userand
where user name like I # { userName} I

当基于不同数据库运行时, MyBatis 会根据配置找到合适的 SQL 去执行,用法就是这么简单。
数据库的更换可能只会引起某个 SQL 语句的部分不同,所以也没有必要使用上面的写法,
而可以使用 if 标签配合默认的上下文中的 databaseid 参数这种写法去实现 这样可以避免
大量重复的 sQL 出现,方便修改。

<select id=” selectByUser” result Type=”tk . mybatis.simple . mode l . SysUser” >select id, user name userName , user password userPassword, user email userEmail , user info userinfo , head_img headimg , create time createTime from sys user <where> <if test=” userName != null and userName ! = ””><if test=”_databaseid == ’ mysql ’”>and user name ke concat ’, #{ userName ,’</if> <if test=”_databaseid == ’ oracle ’”>and user name like I# { userName} I </if> </if><if test=” userEmail !=” and userEmail != null” >and user email = #{userEmail} </if></where> </select>

4、OGNL 用法

MyBatis 的动态 SQL 和${}形式的参数中都用到了 OGNL 表达式 所以我们有必要了解
GNL 的简单用法 MyBatis 常用的 OGNL 表达式如下

  1. el or e2
  2. el and e2
  3. el == e2 el eq e2
    4 . el ! = e2 el neq e2
  4. el lt e2 :小于
  5. el lte e2 :小于等于,其他表示为 gt (大于)、 gte (大于等于)
  6. el + e2 e2 1/e2 1 - e2 e2
  7. ! not :非,取反
  8. e.method(args 调用对象方法)O. e.property 对象属性值
  9. el[ e2 按索引取值( List 、数组和 Map)
  10. @class@method(args ):调用类的静态方法
  11. @class@f eld :调用类的静态字段值

表达式 1-4 是最常用的 种情况。另外有些时候当需要判断一个集合是否为空时,可能会
出现如下判断。

<if test=”l ist !=null and list.size() >。
!一其他一

在这种用法中, list .size ()是调用对象的方法,> 是和数字进行比较。表达式 10 、 l 两种情况也特别常见,而且可以多层嵌套使用。假设 User 类型的属性 user中有 Address 类型的属性名为 addr ,在 Address 中还有一个属性 zipcode ,可以通过user.addr zipcode 直接使用 zipcode 的值。假设 Map 类型的属性为 map ,我们可以通过map [’ userName ’]或 map userName 来获取 map key userName 的值,这里一定要注意,不管 userName 的值是不是 null ,必须保证 userName 这个 key 存在,否则就会报错

表达式 通常用于简化 些校验,或者进行更特殊的校验,例如 if 中常见的判断可以
成如下这样。

<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 I I str.length() == 0;
publ static boolean isNotEmpty(String str) {
return !isEmpty(str) ;
下面举 个特殊点的例子。假设只是在测试的时候想知道映射 XML 中方法执行的 数,
可以先在上面的 StringUtil 中添加如下静态方法。
public static void print(Object parameter) {
System.out.println(parameter);
然后在映射文件中的方法标签内添加如下方法
<bind name= ” print” value=”@ tk. mybatis. util. StringUtil@print ( paramete r )”/>
通过这种方式就能实现 些特殊的功能,这个例子只是为了启发大家,在有些情况下可能
会起到非常好的效果,但是要避免乱用,以免给其他人造成混乱

本章小结

本章通过大量示例详细讲解了 My is 支持的所有动态 SQL 通过动态 SQL 可以避免
Java 代码中处理繁琐的业务逻辑,通过将大量的判断写入到 MyBatis 的映射层可以极大程度上
提高我们的逻辑应变能力。当有 般的业务逻辑改动时,通常只需要在映射 通过动态 SQL
可实现

mybatis从入门到精通(刘增辉著)-读书笔记第四章相关推荐

  1. mybatis从入门到精通(刘增辉著)-读书笔记第五章

    Mybatis 代码生成器 在学习第 MyBatis 的基本用法时,我 写了很多单表的增.删.改.查方法,基本上每个表都要有这些方法 这些方法都很规范并且也比较类似当数据库表的字段 较少的时候,写起来 ...

  2. mybatis从入门到精通(刘增辉著)-读书笔记第三章

    MyBatis 注解方式的基本用法 My ti 注解方式就是将 SQL 语句直接写在接口上.这种方式的优点是 对于需求比较简单的系统,效率较高.缺点是 SQL 有变化时都需要重新编译代码, 般情况下不 ...

  3. mybatis从入门到精通(刘增辉著)-读书笔记第一章

    前言: 本读书笔记共11章节 本版本采用idea编写,不采用作者书中所说的eclipse jdk8 maven3.6.1 mysql5.7 1.idea新建maven项目,配置pom.xml < ...

  4. mybatis从入门到精通(刘增辉著)-读书笔记第二章

    MyBatis XML方式的基本用法 ==我们设定了一个简单的权限控制需求,采用 RBAC (Role-Based Access Control ,基于角色 的访问控制)方式,这个简单的权限管理将会贯 ...

  5. oracle中值集限定词为灰色,《Oracle从入门到精通》读书笔记第四章 SQL语言基础之一...

    4.1 SQL语言概述 4.1.1 SQL语言的特点 1.集合性 2.统一性 3.易于移植性 4.1.2 SQL语言的分类 1.数据查询语言(DQL)- select语句,查询数据 2.数据操纵语言( ...

  6. 《Oracle从入门到精通》读书笔记第四章 SQL语言基础之二

    4.7 事务处理 4.7.1 事务概述 事务的4种属性:acid (1)原子性(atomic):事务是一个整体的工作单元,要么全部执行,要么全部取消. (2)一致性(consistency):所有的数 ...

  7. MyBatis从入门到精通(1):MyBatis入门

    作为一个自学Java的自动化专业211大学本科生,在学习和实践过程中"趟了不少雷",所以有志于建立一个适合同样有热情学习Java技术的参考"排雷手册". 最近在 ...

  8. MyBatis从入门到精通(一):MyBatis入门

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 1. MyBatis简介 ​ 2001 ...

  9. MyBatis从入门到精通 PDF 完整版

    给大家带来的一篇关于MyBatis相关的电子书资源,介绍了关于MyBatis.入门到精通方面的内容,本书是由电子工业出版社出版,格式为PDF,资源大小116.8 MB,刘增辉编写,目前豆瓣.亚马逊.当 ...

最新文章

  1. 运维利器:钉钉机器人脚本告警(Linux Shell 篇)
  2. PostgreSQL: epoch 新纪元时间的使用
  3. xshell 安装yum_本地yum源配置及Xshell连接
  4. 【转】函数调用时堆栈变化
  5. Spring--SPeL
  6. sdut 活动选择问题
  7. 【Java】字符串交叉合并
  8. 人类的悲欢虽不相通,但电脑情感分析模型读得懂
  9. STM32工作笔记045---SystemInit时钟系统初始化函数剖析
  10. 新年新起点-荣获2011年度Silverlight方向Microsoft® MVP奖
  11. 开VM虚拟机导致内存和磁盘利用率高
  12. 深度学习多种模型评估指标介绍 - 附sklearn实现
  13. 动态规划实战7 leetcode-221. Maximal Square
  14. AtCoder Beginner Contest 269笔记
  15. QQ空间说说如何批量删除
  16. Java面试题目分析
  17. Google 就业岗分析
  18. PyPDF2--如何使用python操作你的PDF文档
  19. java 判断生日和当前时间 对比
  20. UE4虚幻引擎UI界面动画制作!

热门文章

  1. C++设计模式 | Factory工厂模式(简单工厂、工厂方法、抽象工厂)
  2. 张勋说:钢渣处理和综合利用的原因及效益分析
  3. Android序列化经典解析(三)-拨乱反正,堪比窦娥的Serializable
  4. 很色,非常色,十分色,格外色,异常色,特别色,相当色,太色了!
  5. 给初学Java的老铁,知道这4点太重要了!
  6. 智能CDN(上):CDN的访问过程和加速原理
  7. 2021年氯化工艺考试报名及氯化工艺考试试卷
  8. LAC+CELLID定位手机位置
  9. c++变幻的矩阵_C++课程设计c++矩阵类(简洁版)
  10. Android新技术——探秘微信小程序