1. 程式人生 > >mybatis入門(四)之動態SQL

mybatis入門(四)之動態SQL

動態 SQL

MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 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”引數值是可以包含一些掩碼或萬用字元的)。       

如果希望通過“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”也設定成動態的條件,看看會發生什麼。

<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% 的情況下都會有用。而在不能使用的地方,你可以自定義處理方式來令其正常工作。一處簡單的修改就能達到目的:

<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 元素為:

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

prefixOverrides 屬性會忽略通過管道分隔的文字序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 屬性中的內容,並且插入 prefix 屬性中指定的內容。

類似的用於動態更新語句的解決方案叫做 setset 元素可以用於動態包含需要更新的列,而捨去其它的。比如:

<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 語句的最後就會有一個逗號遺留)

若你對 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 元素的功能非常強大,它允許你指定一個集合,宣告可以在元素體內使用的集合項(item)和索引(index)變數。它也允許你指定開頭與結尾的字串以及在迭代結果之間放置分隔符。這個元素是很智慧的,因此它不會偶然地附加多餘的分隔符。

注意 你可以將任何可迭代物件(如 List、Set 等)、Map 物件或者陣列物件傳遞給 foreach 作為集合引數。當使用可迭代物件或者陣列時,index 是當前迭代的次數,item 的值是本次迭代獲取的元素。當使用 Map 物件(或者 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>

多資料庫支援

一個配置了“_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>

動態 SQL 中的可插拔指令碼語言   

MyBatis 從 3.2 開始支援可插拔指令碼語言,這允許你插入一種指令碼語言驅動,並基於這種語言來編寫動態 SQL 查詢語句。

可以通過實現以下介面來插入一種語言:

public interface LanguageDriver {
  ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
  SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
  SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}
一旦設定了自定義語言驅動,你就可以在 mybatis-config.xml 檔案中將它設定為預設語言:
<typeAliases>
  <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<settings>
  <setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>

除了設定預設語言,你也可以針對特殊的語句指定特定語言,可以通過如下的 lang 屬性來完成:

<select id="selectBlog" lang="myLanguage">
  SELECT * FROM BLOG
</select>

或者,如果你使用的是對映器介面類,在抽象方法上加上 @Lang 註解即可:

public interface Mapper {
  @Lang(MyLanguageDriver.class)
  @Select("SELECT * FROM BLOG")
  List<Blog> selectBlog();
}

注意 可以將 Apache Velocity 作為動態語言來使用,更多細節請參考 MyBatis-Velocity 專案。

你前面看到的所有 xml 標籤都是由預設 MyBatis 語言提供的,而它由別名為 xml 的語言驅動器 org.apache.ibatis.scripting.xmltags.XmlLanguageDriver 所提供。

相關推薦

mybatis入門動態SQL

動態 SQL MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹

Shell入門數組

定義 col 元素 array 多維 開始 code logs shel 一、一維數組   bash支持一維數組(不支持多維數組),並且沒有限定數組的大小。   類似與C語言,數組元素的下標由0開始編號。 二、定義數組 在Shell中,用括號來表示數組,數組元素用"空格

mybatis入門基礎安裝

安裝 要使用 MyBatis, 只需將 mybatis-x.x.x.jar 檔案置於 classpath 中即可。 如果使用 Maven 來構建專案,則需將下面的 dependency 程式碼置於 pom.xml 檔案中: <dependency>

mybatis入門Mapper XML 檔案

Mapper XML 檔案 MyBatis 的真正強大在於它的對映語句,也是它的魔力所在。由於它的異常強大,對映器的 XML 檔案就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 程式碼進行對比,你會立即發現省掉了將近 95% 的程式碼。MyBatis 就是針對 SQ

mybatis入門Java API

Java API 既然你已經知道如何配置 MyBatis 和建立對映檔案,你就已經準備好來提升技能了。MyBatis 的 Java API 就是你收穫你所做的努力的地方。正如你即將看到的,和 JDBC 相比,MyBatis 很大程度簡化了你的程式碼並保持程式碼簡潔,容易

JavaFX入門Hello World,JavaFX樣式

教你建立和構建JavaFX應用程式的最佳方法是使用“Hello World”應用程式。本教程的另一個好處是,它使您能夠測試您的JavaFX技術是否已正確安裝。 本教程中使用的工具是NetBeans IDE 7.4。在開始之前,請確保您使用的NetBeans IDE版本支

C語言入門switch、迴圈語句

switch格式 switch格式: switch (條件表示式) { case 整數: // case可以有一個或多個 語句; break; case 整數: // case可以有一個或多個 語句;

React Native入門使用Flexbox佈局

前言 flex,收縮,彈性的意思。 彈性(Flex)寬高 關於RN中寬高的設定,我們在上一篇設定Image載入網路圖片的時候提到過,首先width和height是兩個屬性,用來指定一個元件的寬高,使用的時候可以這樣: <Image source

機器學習入門----線性迴歸正規方程

再談最小平方問題 有了矩陣求導工具後,我們可以尋找最小化損失函式的引數值的閉式解(closed-form solution)。首先我們先把這個損失函式表達成向量的形式。 把每個訓練樣本放在矩陣一行,可以得到一個\(m \times n\) 設計矩陣\(X\) (design matrix) ,即 \[ X=\

MyBatis學習XML配置文件SQL映射的XML文件

元素 數據庫 resultmap ash 有一點 oracl 解決 轉換成 插入語 SQL映射文件常用的元素:    1.select   查詢語句是MyBatis最常用的語句之一。   執行簡單查詢的select元素是非常簡單的: <select id=”sele

MyBatis入門—— 輸入映射和輸出映射、動態sql、關聯查詢

輸出類型 sql name屬性 一對一 test HA h標簽 自動 CI p.p4 { margin: 0.0px 0.0px 0.0px 10.0px; font: 10.5px "PingFang SC" } p.p6 { margin: 0.0px 0.0px 0.

精盡MyBatis原始碼分析 - MyBatis初始化 SQL 初始化

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址

精盡MyBatis原始碼分析 - SQL執行過程延遲載入

> 該系列文件是本人在學習 Mybatis 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋([Mybatis原始碼分析 GitHub 地址](https://github.com/liu844869663/mybatis-3)、[Mybatis-Spring 原始碼分析 GitHub 地址

Spring Boot 入門微服務 Config Server 統一配置中心

bootstra pan pat 默認 star default client efault localhost 一、目錄結構 二、pom文件 <!-- 配置服務依賴 --> <dependency> &l

Python入門字符串、字典、集合

Python 字典 1、字符串操作 字符串是無法修改的,只能作為查詢.在python中,加了引號的字符就是字符串類型,python並沒有字符類型。定義:name=‘kim‘ #name=str(‘kim‘) 用於標識:描述性的內容,如姓名,性別,國籍,種族那單引號、雙引號、多引號有什麽區別呢? 讓我

mybatis源碼-解析配置文件配置文件Mapper解析

als cif fragments etc add contex csdn chm element 在 mybatis源碼-解析配置文件(三)之配置文件Configuration解析 中, 講解了 Configuration 是如何解析的。 其中, mappers作為con

NS2入門學習Otcl知識點

面向物件的Tcl語言,物件和類的概念同C++類似。 1.類和物件的定義 % Class  Animal #定義類名 % Animal animal_1#產生類的物件 animal info class =>Animal

T-SQL基礎集合運算

三個運算子 T-SQL支援三個集合運算子:UNION、INTERSECT、EXCEPT。 集合運算子查詢的一般形式如下: Query1 <set_operator> Query2 -- 這裡,ORDER BY子句對最終結果集進行排序 [ORDER BY...] ORDER

mybatis原始碼-解析配置檔案配置檔案Mapper解析

其中, mappers作為configuration節點的一部分配置, 在本文章中, 我們講解解析mappers節點, 即 xxxMapper.xml 檔案的解析。 1 解析入口 在解析 mybatis-config.xml 時, 會進行解析 xxxMapper.xml 的檔案。 在圖示流程的 XMLCo

GPU 程式設計入門到精通 GPU 程式優化

博主由於工作當中的需要,開始學習 GPU 上面的程式設計,主要涉及到的是基於 GPU 的深度學習方面的知識,鑑於之前沒有接觸過 GPU 程式設計,因此在這裡特地學習一下 GPU 上面的程式設計。有志同道合的小夥伴,歡迎一起交流和學習,我的郵箱: [email protected] 。使用的是自