zoukankan      html  css  js  c++  java
  • java版云笔记(九)之动态sql

    SQL

      首先,所谓SQL的动态和静态,是指SQL语句在何时被编译和执行,二者都是用在SQL嵌入式编程中的,这里所说的嵌入式是指将SQL语句嵌入在高级语言中,而不是针对于单片机的那种嵌入式编程。

    静态SQL

      静态SQL通常用于完成可以确定的任务。(即在编译阶段就可以确定数据库要做什么事情。)

    select * from t1 where c1>5
    

      对于上述类似的DML语句在第一次运行时进行编译,而后续再次调用,则不再编译该过程。即一次编译,多次调用,使用的相同的执行计划。此种方式被称之为使用的是静态的SQL。

    注:

    select * from t1 where c1>? and c2<?
    

      这种语句是静态SQL,不是动态SQL,虽然个别参数的值不知道,但整个SQL的结构已经确定,数据库是可以将它编译的,在执行阶段只需将个别参数的值补充进来即可。

    动态SQL

      动态SQL通常是用来根据不同的需求完成不同的任务。(在编译时无法确定,只有等到程序运行起来,在执行的过程中才能确定,这种SQL叫做动态SQL。)

      如preparedStatement对象的execute方法去执行sql语句

    作用:

    • 1 可以支持 DDL 语句, 静态 sql 只能支持 DML 语句.

    • 2 支持web 引用程序的查询意愿( 一个网络应用程序的常见需求是用户可以指定他们想看到的列, 以及改变数据的排序方式 )

    • 3 可以将业务逻辑先放在表中, 然后再动态编译.

      今天我们讲的是关于mybatis的动态sql

      通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。

      动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。

    • if
    • choose (when, otherwise)
    • **trim (where, set) **
    • **foreach **

    if

      动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。比如:

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

      这条语句提供了一个可选的文本查找类型的功能。如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回;反之若传入了“title”,那么就会把模糊查找“title”内容的BLOG结果返回(就这个例子而言,细心的读者会发现其中的参数值是可以包含一些掩码或通配符的)。

      如果想可选地通过“title”和“author”两个条件搜索该怎么办呢?首先,改变语句的名称让它更具实际意义;然后只要加入另一个条件即可。

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

    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>
    

    trim, where, set

      前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在考虑回到“if”示例,这次我们将“ACTIVE = 1”也设置成动态的条件,看看会发生什么。

    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’
    

      这个查询也会失败。这个问题不能简单的用条件句式来解决,如果你也曾经被迫这样写过,那么你很可能从此以后都不想再这样去写了。

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

    <where>包裹 </if>实现正常的查询

    	<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 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。而且,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。

    trim

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

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

      prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它带来的结果就是所有在 prefixOverrides 属性中指定的内容将被移除,并且插入 prefix 属性中指定的内容。

    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>
    

      这里,set 元素会动态前置 SET 关键字,同时也会消除无关的逗号,因为用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号

      若你对等价的自定义 trim 元素的样子感兴趣,那这就应该是它的真面目:

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

      注意这里我们忽略的是后缀中的值,而又一次附加了前缀中的值。

    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 元素的功能是非常强大的,它允许你指定一个集合,声明可以用在元素体内的集合项和索引变量。它也允许你指定开闭匹配的字符串以及在迭代中间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

      注意 你可以将任何可迭代对象(如列表、集合等)和任何的字典或者数组对象传递给foreach作为集合参数。

    •   当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素

    •   当使用字典(或者Map.Entry对象的集合)时,index是键,item是值

      到此我们已经完成了涉及 XML 配置文件和 XML 映射文件的讨论。下一部分将详细探讨 Java API,这样才能从已创建的映射中获取最大利益。

    bind(创建变量并捆绑)

      bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

    	<select id="selectBlogsLike" resultType="Blog">
    	  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
    	  SELECT * FROM BLOG
    	  WHERE title LIKE #{pattern}
    	</select>
    

    Multi-db vendor support(多数据库厂商支持)

      一个配置了“_databaseId”变量的 databaseIdProvider 对于动态代码来说是可用的,这样就可以根据不同的数据库厂商构建特定的语句。比如下面的例子:

    	<insert id="insert">
    	  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    	    <if test="_databaseId == 'oracle'">
    	      select seq_users.nextval from dual
    	    </if>
    	    <if test="_databaseId == 'db2'">
    	      select nextval for seq_users from sysibm.sysdummy1"
    	    </if>
    	  </selectKey>
    	  insert into users values (#{id}, #{name})
    	</insert>
    

      至此,关于云笔记涉及的知识就讲完了,大家可以仔细看看,看那个知识带你没看到可以好好看看

  • 相关阅读:
    JS正则表达式大全(整理详细且实用)
    你真的会使用XMLHttpRequest吗?
    pyCharm最新激活码(2018激活码)
    Hibernate 中配置属性详解(hibernate.properties)
    c3p0详细配置
    使用Git上传本地项目到http://git.oschina.net
    深入理解Java:注解(Annotation)自定义注解入门
    SpringMVC文件上传与下载
    C语言开发系列-二进制
    C开发系列-include
  • 原文地址:https://www.cnblogs.com/yangliguo/p/7627247.html
Copyright © 2011-2022 走看看