SQL mybatis动态查询小结

Posted alomsc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL mybatis动态查询小结相关的知识,希望对你有一定的参考价值。

动态返回mysql某张表指定列的名字

<select id="queryColumns" resultType="map" parameterType="java.util.HashMap">
    select column_name columnName, data_type dataType, column_comment columnComment
    from information_schema.columns
    where table_name = #{tablename}
    and
    column_name  in
    <foreach collection="columnsArray" item="column_name" index="index" open="(" close=")" separator=",">
         #{column_name}
     </foreach>
</select>

动态查询某个表的指定列数据

<select id="query1" resultType="map"  parameterType="java.util.HashMap">
    select
    <foreach collection="columnsArray" item="item" index="index" open=" " separator=", " close=" " >
          ${item}
     </foreach>
     from   #{tableName}   tn
</select> 

利用 if和foreach元素动态的拼接where 条件部分

<select id="query2" resultType="map" parameterType="java.util.HashMap">
        select
        <foreach collection="columnsArray" item="item" index="index" open="" separator="," close="" >
            ${item}
        </foreach>
        from  #{tableName}   db
        where
        1=1
        <if test ="name !=null">
           and      db.name=#{name} 
        </if>
      
 </select>    

传参数 ${} 和#{}区别

Mybatis 的Mapper.xml语句中parameterType向SQL语句传参有两种方式:#{}和${}

我们经常使用的是#{},一般解说是因为这种方式可以防止SQL注入,简单的说#{}这种方式SQL语句是经过预编译的,它是把#{}中间的参数转义成字符串,举个例子:

select * from book where name= #{name} 

预编译后,会动态解析成一个参数标记符?:

select * from book where name= ?

而使用${}在动态解析时候,会传入参数字符串,传入:test,显示为:

select * from student where studentName = ‘test‘

mybatis 一共只需要学习以下几个元素:
-if
-choose(when,otherwise)
-trim(where,set)
-foreach

if

动态SQL通常要做的是根据条件包含where子句的一部分。比如:

<select id="findActiveBlogWithTitleLike"  resultType="Blog">
    SELECT * FROM BLOG
    WHERE state = ‘ok‘
    <if test="title != null">
        AND title = #{title}
    </if>
</select>

choose,when,otherwise

有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

根据上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG(实际情况可能是由管理员按一定策略选出 BLOG 列表,而不是返回大量无意义的随机结果)。

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

 实际上利用if 也可以完成此项工作

 

trim, where, set

回到“if”示例,这次我们将“state = ‘ok‘也设置成动态的条件,看看会发生什么。

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

  这个查询也会失败。这个问题不能简单地用条件句式来解决

解决方式有两种

方式1、

在where 条件后加一个1=1

<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG
    WHERE
    1=1
    <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 1=1

  如果第二个条件匹配 SQL :

SELECT * FROM BLOG
WHERE  1=1
AND title like ‘someTitle’  

方式2、

MyBatis 有一个简单的处理,这在 90% 的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能达到目的:

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

  where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<select id="findActiveBlogLike"   resultType="Blog">
  SELECT * FROM BLOG
<trim prefix="WHERE" prefixOverrides="AND |OR ">
    <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>
  </trim>
</select>

  

 

 

类似的用于动态更新语句的解决方案叫做 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>

  这里,set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(注:因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)加上  <trim prefix="SET" suffixOverrides=","> ... </trim>

<update id="updateAuthorIfNecessary">
  update Author
<trim prefix="set" suffixOverrides=","> 
    <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>

</trim>

where id=#{id}
</update>

  

foreach

动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

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

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

-释义:
-collection :collection属性的值有三个分别是list、array、map三种,分别对应的参数类型为:List、array、map,上面传的参数为数组,所以值为array
-item : 表示在迭代过程中每一个元素的别名
 -index :表示在迭代过程中每次迭代到的位置(下标)
 -open :前缀
 -close :后缀
 -separator :分隔符,表示迭代时每个元素之间以什么分隔
我们通常可以将之用到批量删除、添加等操作中。

注意 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

 

以上是关于SQL mybatis动态查询小结的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis -- 动态Sql概述动态Sql之<if>(包含<where>)动态Sql之<foreach>sql片段抽取

Mybatis关于复杂的SQL查询的处理&Mybatis的缓存机制

Mybatis关于复杂的SQL查询的处理&Mybatis的缓存机制

MyBatis动态SQL标签用法

MyBatis高级特性

MyBatis-05-笔记