Mybatis 坑路4 -> 基於 XML 配置對映器2
基於 XML 配置對映器
配置動態 SQL
有時候,靜態的 SQL 語句並不能滿足應用程式的需求。我們可以根據一些條件,來動態地構建 SQL 語句。
例如,在 Web 應用程式中,有可能有一些搜尋介面,需要輸入一個或多個選項,然後根據這些已選擇的條件去執行檢索操作。在實現這種型別的搜尋功能,我們可能需要根據這些條件來構建動態的 SQL 語句。如果使用者提供了任何輸入條件,我們需要將那個條件新增到 SQL 語句的 WHERE 子句中。
MyBatis 通過使用<if>,<choose>,<where>,<foreach>,<trim>元素提供了對構造動態 SQL 語句的高級別支援。
<if>元素被用來有條件地嵌入 SQL 片段,如果測試條件被複製為 true。則相應的 SQL 片段將會被新增到 SQL 語句中。
SELECT * FROM COURSES WHERE TUTOR_ID=#{tutorId} <if test="courseName != null"> AND NAME LIKE #{courseName} </if> <if test="startDate != null"> AND START_DATE >#{startDate} </if> <if test="endDate != null"> <![CDATA[ AND END_DATE <= #{endDate}]]> </if> <select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES <choose> <when test="searchBy == 'Tutor'"> WHERE TUTOR_ID = #{tutorId} </when> <when test="searchBy == 'CourseName'"> WHERE name like #{courseName} </when> <otherwise> WHERE TUTOR start_date >= now() </otherwise> </choose> </select>
MyBatis 計算 <choose> 測試條件的值,且使用第一個值為 TRUE 的子句。如果沒有條件為 true,則使用<otherwise>內的子句。
有時候,所有的查詢條件應該是可選的。在需要使用至少一種查詢條件的情況下,我們應該使用 WHERE 子句。並且,如果有多個條件,我們需要在條件中新增 AND 或 OR。MyBatis 提供了<where>元素支援這種型別的動態 SQL 語句。
SELECT * FROM COURSES <where> <if test="tutorId != null"> AND TUTOR_ID = #{tutorId} </if> <if test="courseName != null"> AND NAME LIKE #{courseName} </if> <if test="startDate != null"> AND START_DATE >= #{startDate} </if> </where>
<trim>元素和<where>元素類似,但是<trim>提供了在新增字首/字尾或者移出字首/字尾方面提供更大的靈活性。
SELECT * FROM COURSES
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="tutorId != null">
TUTOR_ID = #{tutorId}
</if>
<if test="courseName != null">
AND NAME LIKE #{courseName}
</if>
</trim>
這裡如果任意一個<if>條件為 true,<trim>元素會插入 WHERE,並且移出緊跟 WHERE 後面的 AND 或者 OR
<foreach>可以迭代遍歷一個數組或者列表,構造 AND/OR 條件或一個 IN 子句。
SELECT * FROM COURSES
<if test="tutorIds != null">
<where>
<foreach item="tutorId" collection="tutorIds">
OR TUTOR_ID = #{tutorId}
</foreach>
</where>
</if>
<set>元素和<where>元素類似,如果其內部條件判斷有任何內容返回時,他會插入 SET SQL 片段
UPDATE STUDENTS
<set>
<if test="name != null">name=#{name},</if>
<if test="email != null">email=#{email},</if>
<if test="phone != null">phone=#{phone},</if>
</set>
WHERE STUD_ID = #{id}
如果<if>條件返回了任何文字內容,<set>將會插入 set 關鍵字和其文字內容,並且會剔除末尾的“,”
處理列舉型別
MyBatis 支援開箱方式持久化 enum 型別屬性。假設 STUDENTS 表中有一列 gender 儲存 “MALE” 或者 “FEMALE” 兩種值。並且,Student 物件有一個 enum 型別的 gender 屬性。
預設情況下,MyBatis 使用 EnumTypeHandler 類處理 enum 型別的 Java 屬性,並且將其儲存為 enum 值的名稱。且不需要為此做任何額外的配置,就可以像使用基本資料型別屬性一樣使用 enum 型別屬性。
如果你希望儲存原 enum 的順序位置,而不是 enum 名,則需要明確地配置它。需要在 mybatis-config.xml 檔案中配置 EnumOrdinalTypeHandler:
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="xx.mybatis3.domain.Gender" />
處理 CLOB/BLOB 型別
MyBatis 提供了內建的對 CLOB/BLOB 型別列的對映處理支援。預設情況下,MyBatis 將 CLOB 型別的列對映到 java.lang.String 型別上、而把 BLOB 列對映到 byte[] 型別上。
####傳入多個輸入引數
MyBatis 中的對映語句有一個 parameterType 屬性來制定輸入引數的型別。如果我們想給對映語句傳入多個引數的話,可以將所有的輸入引數放到 HashMap 中,將 HashMap 傳遞給對映語句。
MyBatis 還提供了另外一種傳遞多個輸入引數給對映語句的方法。假設我們想通過給定的 name 和 email 資訊查詢學生資訊,定義查詢介面如下:
List<Student> findAllStudentByNameAndEmail(String name,String email);
<select id="findAllStudentByNameAndEmail" resultMap="StudentResult">
SELECT STUD_ID,NAME,EMAIL,PHONE FROM STUDENTS WEHRE NAME=#{param1} AND EMAIL=#{param2}
</select>
這裡的 #{param1} 引用第一個引數 name,而 #{param2} 引用了第二個引數 email。
MyBatis 還提供了一種傳遞多個輸入引數給對映語句的方法。是通過使用 @Param 註解:
List<Student> findAllStudentByNameAndEmail(@Param("name")String name,@Param("email")String email);
<select id="findAllStudentByNameAndEmail" resultMap="StudentResult">
SELECT STUD_ID,NAME,EMAIL,PHONE FROM STUDENTS WHERE NAME=#{name} AND EMAIL=#{email}
</select>
快取
將從資料庫中載入的資料快取到記憶體中,是很多應用程式為了提高效能而採取的一貫做法。MyBatis 對通過對映的 SELECT 語句載入的查詢結果提供了內建的快取支援。預設情況下,啟用一級快取:即,一級快取基於 PerpetualCache 的 HashMap 本地快取,其儲存作用域為 SqlSession,當 Session flush 或 close 之後,該 Session 中的所有 Cache 就將清除。
我們可以在 SQL 對映器 XML 配置檔案中使用 <cache />元素新增全域性二級快取。其儲存作用域為 Mapper(Namespace)。
當加入了<cache />元素,將會出現以下情況:
所有的在對映語句檔案定義的<select>語句的查詢結果都會被快取
所有的在對映語句檔案定義的<insert>,<update>和<delete>語句將會重新整理快取
快取根據最近最少被使用(Least Recently Used,LRU)演算法管理
快取不會被任何形式的基於時間表的重新整理(沒有重新整理時間間隔),即不支援定時重新整理機制
快取將儲存 1024 個查詢方法返回的列表或者物件的引用
快取會被當作一個讀/寫快取。這是指檢索出的物件不會被共享,並且可以被呼叫者安全地修改,不會受其他潛在的呼叫者或者執行緒的潛在修改干擾。(即,快取是執行緒安全的)
也可以通過複寫預設屬性來自定義快取的行為:
<chache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
- eviction:此處定義快取的移出機制。預設值是 LRU,其可能的值有:LRU(least recently used,最近最少使用),FIFO(first in first out,先進先出),SOFT(soft reference,軟引用),WEAK(weak reference,弱引用)。
flushInterval:定義快取重新整理間隔,以毫秒計。預設情況下不設定。所以不使用重新整理間隔,快取 cache 只有呼叫語句的時候重新整理。- size:此表示快取 cache 中能容納的最大元素數。預設值是 1024,你可以設定成任意的正整數。
- readOnly:一個只讀的快取 cache 會對所有的呼叫者返回被快取物件的同一個例項(實際返回的是被返回物件的一份引用)。一個讀/寫快取 cache 將會返回被返回物件的一份拷貝(通過序列化)。預設情況下設定為 false。可能的值有 false 和 true。
預設的對映語句的 cache 配置如下:
<select... flushCache="false" userCache="true" />
<insert... flushCache="true" />
<update... flushCache="true" />
<delete... flushCache="true" />
MyBatis 使用 Ehcache 快取
官網上提供了一個 MyBatis-ehcache.jar 的包用於整合 ehcache 快取,文件中還說明需要一個 ehcache-core.jar 的包,除了這兩個包之外有幾個包也是必須的,官方並沒有說明,以下是需要加入的所有和 ehcache 相關的包:
1.ehcache-core-2.4.4.jar
2.mybatis-ehcache-1.0.0.jar
3.slf4j-api-1.6.1.jar
4.slf4j-log4j12-1.6.2.jar
當然也可以直接在 Maven 構建工具中使用
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
新建一個 Ehcache 的配置檔案,該檔名必須為 ehcache.xml,放在類路徑下面。
Sql mapper 配置檔案裡面加入以下內容(二選一)
<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />會輸出日誌
<cache type="org.mybatis.caches.ehcache.EhcacheCache" />不會輸出日誌