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 包括以下幾種元素,如下表所示
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 中屬性說明如下
示例
<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>