天天看點

「Java知識」Mybatis的特性詳解——動态SQL,拿走不謝

作者:java聯網架構師

Mybatis的特性詳解——動态SQL

  • 1.MyBatis if标簽:條件判斷
  • 2.MyBatis choose、when和otherwise标簽
  • 5.MyBatis foreach标簽
  • 仰天大笑出門去,我輩豈是蓬蒿人

動态 SQL 是 MyBatis 的強大特性之一。在 JDBC 或其它類似的架構中,開發人員通常需要手動拼接 SQL 語句。根據不同的條件拼接 SQL 語句是一件極其痛苦的工作。例如,拼接時要確定添加了必要的空格,還要注意去掉清單最後一個列名的逗号。而動态 SQL 恰好解決了這一問題,可以根據場景動态的建構查詢。

動态 SQL 隻有幾個基本元素,與 JSTL 或 XML 文本處理器相似,十分簡單明了,大量的判斷都可以在 MyBatis 的映射 XML 檔案裡配置,以達到許多需要大量代碼才能實作的功能。

好處: :動态 SQL 大大減少了編寫代碼的工作量,更展現了 MyBatis 的靈活性、高度可配置性和可維護性。

一、動态sql的元素

MyBatis 的動态 SQL 包括以下幾種元素,如下表所示

「Java知識」Mybatis的特性詳解——動态SQL,拿走不謝

1.MyBatis if标簽:條件判斷

MyBatis if 類似于 Java 中的 if 語句,是 MyBatis 中最常用的判斷語句。使用 if 标簽可以節省許多拼接 SQL 的工作,把精力集中在 XML 的維護上。 if 語句使用方法簡單,常常與 test 屬性聯合使用。

文法如下:

<if test="判斷條件">
    SQL語句
</if>           

當判斷條件為 true 時,才會執行所包含的 SQL 語句。

最常見的場景是在 if 語句中包含 where 子句,例如。

<select id="selectAllBaseData" resultMap="myResult">
    select id,name from baseData
    <if test="name != null">
        where name like #{name}
    </if>
</select>           

以上代表表示根據name去查找相應的資訊,但是name是一個可填可不填的條件,不填寫的時候不作為查詢條件。

可多個 if 語句同時使用。以下語句表示為可以按照 name 或者 id 進行模糊查詢。如果您不輸入,則傳回所有的記錄。但是,如果你傳遞了任意一個參數,它就會傳回與給定參數相比對的記錄:

<select id="selectAllBaseData" resultMap="myResult">
    select id,name from baseData
    <if test="name != null">
        where name like #{name}
    </if>
    <if test="id != id">
        AND id like #{id}
    </if>
</select>           

2.MyBatis choose、when和otherwise标簽

MyBatis 中動态語句 choose-when-otherwise 類似于 Java 中的 switch-case-default 語句。由于 MyBatis 并沒有為 if 提供對應的 else 标簽,如果想要達到 <if>...<else>...</else> </if> 的效果,可以借助 <choose>、<when>、<otherwise> 來實作。

動态語句 choose-when-otherwise 文法如下。

<choose>
    <when test="判斷條件1">
        SQL語句1
    </when >
    <when test="判斷條件2">
        SQL語句2
    </when >
    <when test="判斷條件3">
        SQL語句3
    </when >
    <otherwise>
        SQL語句4
    </otherwise>
</choose>           

choose 标簽按順序判斷其内部 when 标簽中的判斷條件是否成立,如果有一個成立,則執行相應的SQL 語句,choose 執行結束;

如果都不成立,則執行 otherwise 中的 SQL 語句。

這類似于 Java 的 switch 語句;

  • choose 為 switch,
  • when 為 case,
  • otherwise 則為 default。

示例

以下示例要求:

當網站名稱不為空時,隻用網站名稱作為條件進行模糊查詢;

當網站名稱為空,而網址不為空時,則用網址作為條件進行模糊查詢;

當網站名稱和網址都為空時,則要求網站年齡不為空.

<mapper namespace="net.biancheng.mapper.WebsiteMapper">
    <select id="selectWebsite">
        SELECT id,name,url,age,country
        FROM website WHERE 1=1
        <choose>
            <when test="name != null and name !=''">
                AND name LIKE CONCAT('%',#{name},'%')
            </when>
            <when test="url != null and url !=''">
                AND url LIKE CONCAT('%',#{url},'%')
            </when>
            <otherwise>
                AND age is not null
            </otherwise>
        </choose>
    </select>
</mapper>           

這樣 MyBatis 就會根據參數的設定進行判斷來動态組裝 SQL,以滿足不同業務的要求。遠比 Hibernate 和 JDBC 中大量判斷 Java 代碼要清晰和明确。

3.MyBatis where标簽

where 标簽

where 标簽主要用來簡化 SQL 語句中的條件判斷,可以自動處理 AND/OR 條件,文法如下

<where>
    <if test="判斷條件">
        AND/OR ...
    </if>
</where>           

if 語句中判斷條件為 true 時,where 關鍵字才會加入到組裝的 SQL 裡面,否則就不加入。where 會檢索語句,它會将 where 後的第一個 SQL 條件語句的 AND 或者 OR 關鍵詞去掉。

示例

<select id="selectWebsite" resultType="net.biancheng.po.Website">
    select id,name,url from website
    <where>
        <if test="name != null">
            AND name like #{name}
        </if>
        <if test="url!= null">
            AND url like #{url}
        </if>
    </where>
</select           

4.MyBatis set标簽

在 Mybatis 中,update 語句可以使用 set 标簽動态更新列。set 标簽可以為 SQL 語句動态的添加 set 關鍵字,剔除追加到條件末尾多餘的逗号。 代碼如下。

<!--使用set元素動态修改一個網站記錄 -->
    <update id="updateWebsite">
        UPDATE website
        <set>
            <if test="name!=null">name=#{name},</if>
            <if test="url!=null">url=#{url},</if>
        </set>
        WHERE id=#{id}
    </update>           

5.MyBatis foreach标簽

對于一些 SQL 語句中含有 in 條件,需要疊代條件集合來生成的情況,可以使用 foreach 來實作 SQL 條件的疊代。

Mybatis foreach 标簽用于循環語句,它很好的支援了資料和 List、set 接口的集合,并對此提供周遊的功能。文法格式如下。

<foreach item="item" index="index" collection="list|array|map key" open="(" separator="," close=")">
   #{item}
</foreach>           

foreach 标簽主要有以下屬性,說明如下:

  • item:表示集合中每一個元素進行疊代時的别名。
  • index:指定一個名字,表示在疊代過程中每次疊代到的位置。
  • open:表示該語句以什麼開始(既然是 in 條件語句,是以必然以(開始)。
  • separator:表示在每次進行疊代之間以什麼符号作為分隔符(既然是 in 條件語句,是以必然以,作為分隔符)。
  • close:表示該語句以什麼結束(既然是 in 條件語句,是以必然以)開始)。

使用 foreach 标簽時,最關鍵、最容易出錯的是 collection 屬性,該屬性是必選的,但在不同情況下該屬性的值是不一樣的,主要有以下 3 種情況:

  • 如果傳入的是單參數且參數類型是一個 List,collection 屬性值為 list。
  • 如果傳入的是單參數且參數類型是一個 array 數組,collection 的屬性值為 array。
  • 如果傳入的參數是多個,需要把它們封裝成一個 Map,當然單參數也可以封裝成 Map。Map 的 key 是參數名,collection 屬性值是傳入的 List 或 array 對象在自己封裝的 Map 中的 key。

示例

修改array裡面id為這些的資料status改為0

update project set status = 0 where id in
  <foreach item="id" collection="array" open="(" separator="," close=")">
      #{id}
  </foreach>           

注意事項:在使用 foreach 标簽時,應提前預估一下 collection 對象的長度。因為大量資料的 in 語句會影響性能,且還有一些資料庫會限制執行的 SQL 語句長度。

6.MyBatis bind标簽

每個資料庫的拼接函數或連接配接符号都不同,例如 MySQL 的 concat 函數、Oracle 的連接配接符号“||”等。這樣 SQL 映射檔案就需要根據不同的資料庫提供不同的實作,顯然比較麻煩,且不利于代碼的移植。MyBatis 提供了 bind 标簽來解決這一問題。

bind 标簽可以通過 OGNL 表達式自定義一個上下文變量。

比如,按照網站名稱進行模糊查詢,SQL 映射檔案如下。

<select id="selectWebsite" >
    <bind name="pattern" value="'%'+_parameter+'%'" />
    SELECT id,name,url,age,country
    FROM website
    WHERE name like #{pattern}
</select>           

bind 元素屬性如下:

  • value:對應傳入實體類的某個字段,可以進行字元串拼接等特殊處理。
  • name:給對應參數取的别名。

以上代碼中的“_parameter”代表傳遞進來的參數,它和通配符連接配接後,賦給了 pattern,然後就可以在 select 語句中使用這個變量進行模糊查詢,不管是 MySQL 資料庫還是 Oracle 資料庫都可以使用這樣的語句,提高了可移植性。

大部分情況下需要傳遞多個參數,下面為傳遞多個參數時 bind 的用法示例。

示例

//mapper檔案中入參
public List<User> selectUser(User user);
-- xml中
<select id="selectUser" resultType="User">
    <bind name="pattern_name" value="'%'+name+'%'" />
    <bind name="pattern_url" value="'%'+url+'%'" />
    SELECT id,name,url,age,country
    FROM User
    WHERE name like #{pattern_name}
    AND url like #{pattern_url}
</select>           

7.MyBatis trim标簽

在 MyBatis 中除了使用 if+where 實作多條件查詢,還有一個更為靈活的元素 trim 能夠替代之前的做法。

trim 一般用于去除 SQL 語句中多餘的 AND 關鍵字、逗号,或者給 SQL 語句前拼接 where、set 等字尾,可用于選擇性插入、更新、删除或者條件查詢等操作。trim 文法格式如下。

<trim prefix="字首" suffix="字尾" prefixOverrides="忽略字首字元" suffixOverrides="忽略字尾字元">
    SQL語句
</trim>           

trim 中屬性說明如下

「Java知識」Mybatis的特性詳解——動态SQL,拿走不謝

示例

<select id="selectUser" resultType="User">
    SELECT id,name,url,age,country
    FROM User
    <trim prefix="where" prefixOverrides="and">
        <if test="name != null and name !=''">
            AND name LIKE CONCAT ('%',#{name},'%')
        </if>
        <if test="url!= null">
            AND url like concat ('%',#{url},'%')
        </if>
    </trim>
</select>           

需要Java資料和面試題:轉發+關注之後,私信【Java】即可!!!