学会动态SQL,MyBatis更上一层楼!

动态 SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

MyBatis的动态sql主要是通过MyBatis动态sql标签来实现的,主要的元素标签有以下几个

 - if
 - choose ,when,,otherwise
 - trim ,where,set
 - foreach

下面就详细介绍下各个标签元素的使用

if标签

动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分,所以在 MyBatis 中 元素是最常用的元素,它类似于 Java 中的 if 语句。

if标签是通过test子句的结果来判断是否拼接if标签内的sql语句,如果test语句为true则拼接,如果为false则不拼接

下面是一个简单例子,大家可以参考

<!--使用 if 元素根据条件动态查询用户信息-->
<select id="selectUserByIf" resultType="com.po.MyUser" parameterType="com.po.MyUser">
    select * from user where 1=1
    <if test="uname!=null and uname!=''">
        and uname like concat('%',#{uname},'%')
    </if >
    <if test="usex !=null and usex !=''">
        and usex=#{usex}
    </if >
</select>

上面的例子,只有当uname和usex 参数不为null而且不为空字符串的时候才会拼接对应的sql语句

if标签的使用总结:

1if标签的test属性必填,test属性为一个判断表达式,结果返回truefalse

2、判断条件!= null== null,适用于任何类型的字段,用于判断某个属性是否为空

3、test属性表达式有多个判断条件时,使用andor进行连接,and相当于Java的与(&&)运算符,需要and连接的两个条件都为true才返回trueor相当于Java的或(||)运算符,两个条件中有一个为true,则返回true

choose标签

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

choose标签是通过choose标签内的标签来拼接sql语句,如果标签的判断表达式返回为true,则拼接该标签内的sql,并且会结束choose,这意味着choose只会选择一个符合条件的sql进行拼接,这就意味着哪怕一个choose标签内有多个符合条件的标签,它也只会选择第一个标签的sql语句。choose标签还有一个otherwise 标签,当 choose 中所有 when 的条件都不满则时,则拼接 otherwise 中的sql。

示例:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <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>
</select>

上面的例子,当传入了 “title” 就会按 “title” 查找,传入了 “author” ,就按 “author” 查找。若两者都没有传入,就添加featured 为1的条件

where标签

where 标签元素只会在子元素有返回内容的时候下才插入 “WHERE” 关键字。而且,如果第一个子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

这是为了解决以下问题

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:

SELECT * FROM BLOG
WHERE

这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

这个查询也会失败,这个问题不能简单地用条件元素来解决。但是我们用where标签就可以轻松解决上述问题

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

set标签

set 标签元素主要是用在更新操作的时候,它的主要功能和 where 标签元素其实是差不多的,主要是在包含的语句前输出一个 set,然后如果包含的语句是以逗号结束的话将会把该逗号忽略,如果 set 包含的内容为空的话则会出错。有了 set 元素就可以动态的更新那些修改了的字段。

例:

<update id="updateAuthorIfNecessary">
  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}
</update>

特别需要注意, 标签包含的内容不能为空,比如上面的例子,如果我们的if标签都为false,则内容为空,那么拼接的sql就是

 update Author  where id=#{id}

这样的sql语句明显是错误的

trim标签

trim标签是一个格式化的标签,主要用于拼接sql的条件语句(前缀或后缀的添加或忽略),它的灵活性较高,可以完成set或者是where标签的功能。以下是trim标签的四个主要的属性:

prefix:前缀内容,即会在trim语句前添加prefix指定的字符串

suffix:后缀内容,即会在trim语句后添加suffix指定的字符串

prefixOverrides:去除sql语句前面的某个关键字或者字符,比如当该属性指定为"AND",当trim拼接的sql语句的开头为"AND",trim标签将会去除该"AND"

suffixOverrides:去除sql语句前面的某个关键字或者字符,比如当该属性指定为","(逗号),当trim拼接的sql语句的结尾为","(逗号)时,trim标签将会去除该","(逗号)

比如,我们可以使用以下trim标签语句可以代替where标签

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

使用以下trim标签语句可以代替set标签

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

foreach标签

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

foreach元素的属性主要有item,index,collection,open,separator,close。

item:当前迭代到的元素的别名,该参数为必选。

index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选

open:foreach代码的开始符号,一般是”(“,和close=")"合用。常用在in(),values()时。该参数可选
separator:元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。

close: foreach代码的关闭符号,一般是)open="("合用。常用在in(),values()时。该参数可选。

collection: 要做foreach遍历的对象,如果遍历对象为List对象,collection 属性值为"list",
如果遍历对象为 array 数组,collection 属性值为"array",
Map对象没有默认的键,当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效,使用map中的键名作为collection 的属性值。 
除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个时候collection 就为collection = "ids".如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id"

在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:

1、如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .
2、如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
3、如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.

示例:

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

猜你喜欢

转载自blog.csdn.net/qq_36551991/article/details/112207105