MyBatis系列五 动态SQL

如果使用JDBC或者其他框架,很多时候你得根据需要去拼装SQL,这是一个麻烦的 事情。而MyBatis提供对SQL语句动态的组装能力,而且它只有几个基本的元素,十分简

单明了,大量的判断都可以在MyBatis的映射XML文件里面配置,以达到许多我们需要 大量代码才能实现的功能,大大减少了我们编写代码的工作量,这体现了 MyBatis的灵活

性、高度可配置性和可维护性。MyBatis也可以在注解中配置SQL,但是由于注解中配置 功能受限,对于复杂的SQL而言可读性很差,所以使用较少,因此在将不对它们进行 介绍。

 

一、概述

   MyBatis的动态SQL包括以下几种元素,如表5-1所示。

 

表5・1动态SQL的元素

元 素

作 用

备 注

if

判断语句

单条件分支判断

choose (when、otherwise)

相当于Java中的case when语句

多条件分支判断

trim (where set)

辅助元素

用于处理一些SQL拼装问题

fbreach

循环语句

在in语句等列举条件常用

下面我们就讨论这些动态元素的用法。

二、if元素

  if元素是我们最常用的判断语句,相当于Java中的if语句。它常常与test属性联合使用。

  在大部分情况下,if元素使用方法简单,让我们先了解它的基本用法。现在我们要根 据角色名称(roleName)去查找角色,但是角色名称是一个可填可不填的条件,不填写的 时候就不要用它作为查询条件。这是查询中常见的场景之一。if元素提供了简易的实现方 法,如代码清单5.1所示。

  这句话的含义就是当我们将参数roleName传递进入到映射器中,采取构造对roleName 的模糊查询。如果这个参数为空,就不要去构造这个条件,显然这样的场景在我们实际的 工作中是十分常见的。通过MyBatis的条件语句我们可以节省许多拼接SQL的工作,把精 力集中在XML的维护上。

三、choose、when, otherwise 元素

5.2节的例子相对于Java语言中的if语句就是一种非此即彼的关系,但是很多时候我 们所面对的不是一种非此即彼的选择。在有些时候我们还需要第三种选择甚至更多的选择, 也就是说,我们也需要switch...case...default语句,而在映射器的动态语句中choose、 when、 otherwise元素承担了这个功能,让我们看看下面的场景。

  • 当角色编号不为空,则只用角色编号作为条件查询。
  • 当角色编号为空,而角色名称不为空,则用色名称作为条件进行模糊查询。
  • 当角色编号和角色名称都为空,则要求角色备注不为空。

让我们看看如何使用choose、when、otherwise元素去实现,如代码清单5.2所示。

  这样MyBatis就会根据参数的设置进行判断来动态组装SQL,以满足不同业务的要求。 远比Hibernate和JDBC大量判断Java代码要清晰和明确得多。

 四、trim、where、set 兀素

  细心的读者会发现5.3节的SQL语句笔者加入了一个条件“ 1=1 ”,如果没有加入这个 条件,那么可能就变为了下面这样一条错误的语句。

  显然就会报错关于SQL的语法异常。而加入了 “1=1”这样的条件又显得相当奇怪。 不过不必担心,我们可以用where元素去处理SQL以达到预期的效果。例如我们去掉了条 “1=1”,只要用where元素就可以了,如代码清单5.3所示。

 

  这样当where元素里面的条件成立的时候,才会加入where这个SQL关键字到组装的 SQL里面,否则就不加入。

  有时候我们要去掉一些特殊的SQL语法,比如常见的and、or。而使用trim元素可以 达到我们预期的效果,如代码清单5.4所示。

  稍微解释一下,trim元素就意味着我们需要去掉一些特殊的字符串,prefix代表的是语 句的前缀,而prefixOverrides代表的是你需要去掉的那种字符串。上面的写法基本与where 是等效的。

  在Hibernate中我们常常需要更新某一对象,发送所有的字段给持久对象。现实中的场 景常常是,我只想更新一个字段,如果发送所有的属性去更新一遍,对网络带宽消耗较大, 性能最佳的办法是把主键和更新字段的值传递给SQL更新即可。例如,角色表有一个主键 和两个字段,如果一个个去更新需要写2条SQL,如果有1000个字段呢?显然这种做法是 不方便的,而在Hibernate中我们做更新都是用全部字段发送给SQL的方法来避免这一情 况发生。

  在MyBatis中,我们常常可以使用set元素来完成这些功能,如代码清单5.5所示。

  set元素遇到了逗号,它会把对应的逗号去掉,如果我们自己编写那将是多少次的判断 呢?当我们只想更新备注,我们只需要传递备注信息和角色编号即可,而不需要再传递角 色名称。MyBatis就会根据参数的规则进行动态SQL组装,这样便能满足要求,同时避免 了全部字段更新的麻烦。

  同样的你也可以把它转变为对应的trim元素,代码如下。

 

 五、foreach 元

  显然foreach元素是一个循环语句,它的作用是遍历集合。它能够很好的支持数组和 List、Set接口的集合,对此提供遍历的功能。

  在数据库中,数据字典是经常使用的内容,比如在用户表中,性别可以分为男、女或 者未知,我们把性别作为一个字典,定义如下。

    1 .男,2.女,0.未知

  实际工作中,用户可能查找非未知性别的用户,也可能查找女性和未知性别的用户, 或者男性和未知性别的用户等,具体的参数需要使用foreach元素去确定,如代码清单5.6 所示。

这里需要稍微解释一下。

  • collection配置的sexList是传递进来的参数名称,它可以是一个数组或者List、Set 等集合。
  • item配置的是循环中当前的元素。
  • index配置的是当前元素在集合的位置下标。
  • open和close配置的是以什么符号将这些集合元素包装起来。
  • separator是各个元素的间隔符。

  在SQL中对于in语句我们常常使用,对于大量数据的in语句需要我们特别注意,因 为它会消耗大量的性能,还有一些数据库的SQL对执行的SQL长度也有限制。所以我们 使用它的时候需要预估一下这个collection对象的长度。

六、test的属性

  test的属性用于条件判断的语句中,它在MyBatis中广泛使用。它的作用相当于判断真 假。在大部分的场景中我们都是用它判断空和非空。有时候我们需要判断字符串、数字和 枚举等。所以十分有必要讨论一下它的用法。通过5.2节对if元素的介绍,我们知道了如 何判断非空。但是如何用if语句判断字符串呢?我们对代码进行下面的测试,如代码清 5.7所示。

  把type= "Y”传递给这条SQL,我们发现程序自动加入了 where 1=1。换句话说,这条语句判定成功了。在旧的版本里面我们往往需要加入toString(),新的版本已经解决了这个问题。同样的它可以给我们判断数值型的参数。对于枚举而言,取决 于你使用何种typeHandler,这些需要参考第3章关于枚举typeHandler的介绍。

七、bind 兀素

 

  bind元素的作用是通过OGNL表达式去自定义一个上下文变量,这样更方便我们使 用。在我们进行模糊查询的时候,如果是MySQL数据库,我们常常用到的是一个concat “%”和参数相连接。然而在Oracle数据库则是用连接符号“||”,这样SQL就需要提供 两种形式去实现。但是有了 bind元素,我们就完全不必使用数据库的语言,只要使用MyBatis 的语言即可与所需参数相连。

  比如我们要按角色名称进行模糊查询,我们可以把映射文件写成这样,如代码清单5.8 所示。

  这里的".parameter”代表的就是传递进来的参数,它和通配符连接后,赋给了 pattern, 我们就可以在select语句中使用这个变量进行模糊查询,不管是MySQL数据库还是Oracle 数据库都可以使用这样的语句,提高了其可移植性。

  我们传递的参数往往不止这么一个,我们可能传递多个参数。让我们来学习多个参数bind元素的用法。首先,定义接口方法,如代码清单5.9所示。

代码5-9使用bind元素传递多个参数

 

*查询角色
*@param roleName 角色名称
*@param note 备注
* @return符合条件的角色
*/
public List<RoleBean> findRole(@Param("roleName")String roleName, @Param (”note”)String note);

  然后,定义映射文件,定义两个新的变量去执行模糊查询,如代码清单5.10所示。

 

 

 

 

 

posted @ 2020-09-04 01:44  跃小云  阅读(217)  评论(0编辑  收藏  举报