一、什麼是查詢快取
mybatis提供查詢快取,用於減輕資料壓力,提高資料庫效能。
mybaits提供一級快取,和二級快取。
1.1. 一級快取是sqlSession級別的快取。在運算元據庫時需要構造sqlSession物件,在物件中有一個資料結構(HashMap),用於儲存快取資料。不同的sqlSession之間的快取 區域(HashMap)是互不影響的。
1.2. 二級快取是mapper級別的快取,多個sqlSession去操作同一個Mapper的sql語句,多個SqlSession可以公用二級快取,二級快取是跨sqlSession的。
1.3. 為什麼要用快取?
如果快取中有資料就不用從資料庫中獲取,減少了和資料之間的互動次數,大大提高系統的效能。
二、一級快取
2.1. 一級快取的工作原理
a. 第一次發起查詢使用者id為1的使用者資訊,先去找快取中是否有id為1的使用者資訊,如果沒有,從資料庫查詢使用者資訊。
得到使用者資訊,將使用者資訊儲存到一級快取中。
b. 如果sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級快取,這樣做的目的為了讓快取中儲存的是最新的資訊,
避免髒讀。
c. 第二次發起查詢使用者id為1的使用者資訊,先去找快取中是否有id為1的使用者資訊,快取中有,直接從快取中獲取使用者資訊。
mybatis預設支援一級快取的。測試很簡單,這裡就不貼程式碼了。
2.2.一級快取的應用
正式開發,假如專案是將mybatis和spring進行整合開發....,事務控制在service中。
一個service方法中包括 很多mapper方法呼叫。
service{
//開始執行時,開啟事務,建立SqlSession物件
//第一次呼叫mapper的方法findUserById(1)
//第二次呼叫mapper的方法findUserById(1),從一級快取中取資料
//方法結束,sqlSession關閉
}
如果是執行兩次service呼叫查詢相同 的使用者資訊,不走一級快取,因為session方法結束,sqlSession就關閉,一級快取就清空。
三、二級快取
3.1二級快取的工作原理
3.1.1. 首先開啟mybatis的二級快取。
3.1.2. sqlSession1去查詢使用者id為1的使用者資訊,查詢到使用者資訊會將查詢資料儲存到二級快取中。
3.1.3. 如果SqlSession3去執行相同 mapper下sql,執行commit提交,清空該 mapper下的二級快取區域的資料。
3.1.4. sqlSession2去查詢使用者id為1的使用者資訊,去快取中找是否存在資料,如果存在直接從快取中取出資料。
二級快取與一級快取區別,二級快取的範圍更大,多個sqlSession可以共享一個UserMapper的二級快取區域。
UserMapper有一個二級快取區域(按namespace分) ,其它mapper也有自己的二級快取區域(按namespace分)。
每一個namespace的mapper都有一個二快取區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到資料將存在相同的二級快取區域中。
3.2. 開啟二級快取
mybaits的二級快取是mapper範圍級別,除了在SqlMapConfig.xml設定二級快取的總開關,還要在具體的mapper.xml中開啟二級快取。
在核心配置檔案SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
|
描述 |
允許值 |
預設值 |
cacheEnabled |
對在此配置檔案下的所有cache 進行全域性性開/關設定。 |
true false |
true |
a.在mybatis的核心配置檔案sqlMapConfig.xml中開啟二級快取,其實預設值就為true,寫上方便程式碼維護。
<!-- 全域性引數的配置 -->
<settings>
<!-- 開啟二級快取 -->
<setting name="cacheEnabled" value="true"/>
</settings>
b.實體類User實現序列化介面
public class User implements Serializable{
//屬性......
//getter and setter......
}
為了將快取資料取出執行反序列化操作,因為二級快取資料儲存介質多種多樣,不一樣在記憶體。
c.Junit測試:
// 二級快取測試
@Test
public void testCache2() throws Exception {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
// 建立代理物件
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
// 第一次發起請求,查詢id為1的使用者
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//這裡執行關閉操作,將sqlsession中的資料寫到二級快取區域
sqlSession1.close();
//使用sqlSession3執行commit()操作
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user = userMapper3.findUserById(1);
user.setUsername("張明明"); userMapper3.updateUser(user);
//執行提交,清空UserMapper下邊的二級快取
sqlSession3.commit();
sqlSession3.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
// 第二次發起請求,查詢id為1的使用者
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
3.3.禁用二級快取
在statement中設定useCache=false可以禁用當前select語句的二級快取,即每次查詢都會發出sql去查詢,預設情況是true,即該sql使用二級快取。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
3.4.重新整理快取
在mapper的同一個namespace中,如果有其它insert、update、delete運算元據後需要重新整理快取,如果不執行重新整理快取會出現髒讀。
設定statement配置中的flushCache="true" 屬性,預設情況下為true即重新整理快取,如果改成false則不會重新整理。使用快取時如果手動修改資料庫表中的查詢資料會出現髒讀。
如下:
<insert id="insertUser" parameterType="com.mybaits.entity.User" flushCache="true">
3.5.Mybatis Cache引數
lushInterval(重新整理間隔)可以被設定為任意的正整數,而且它們代表一個合理的毫秒形式的時間段。預設情況是不設定,也就是沒有重新整理間隔,快取僅僅呼叫語句時重新整理。
size(引用數目)可以被設定為任意正整數,要記住你快取的物件數目和你執行環境的可用記憶體資源數目。預設值是1024。
readOnly(只讀)屬性可以被設定為true或false。只讀的快取會給所有呼叫者返回快取物件的相同例項。因此這些物件不能被修改。這提供了很重要的效能優勢。可讀寫的快取會返回快取物件的拷貝(通過序列化)。這會慢一些,但是安全,因此預設是false。
如下例子:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
這個更高階的配置建立了一個 FIFO 快取,並每隔 60 秒重新整理,存數結果物件或列表的 512 個引用,而且返回的物件被認為是隻讀的,因此在不同執行緒中的呼叫者之間修改它們會導致衝突。可用的收回策略有, 預設的是 LRU:
- LRU – 最近最少使用的:移除最長時間不被使用的物件。
- FIFO – 先進先出:按物件進入快取的順序來移除它們。
- SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的物件。
- WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的物件。
3.6.二級快取應用場景
對於訪問多的查詢請求且使用者對查詢結果實時性要求不高,此時可採用mybatis二級快取技術降低資料庫訪問量,提高訪問速度,業務場景比如:耗時較高的統計分析sql、電話賬單查詢sql等。
實現方法如下:通過設定重新整理間隔時間,由mybatis每隔一段時間自動清空快取,根據資料變化頻率設定快取重新整理間隔flushInterval,比如設定為30分鐘、60分鐘、24小時等,根據需求而定。
3.7.二級快取的侷限性
mybatis二級快取對細粒度的資料級別的快取實現不好,比如如下需求:對商品資訊進行快取,由於商品資訊查詢訪問量大,但是要求使用者每次都能查詢最新的商品資訊,此時如果使用mybatis的二級快取就無法實現當一個商品變化時只重新整理該商品的快取資訊而不重新整理其它商品的資訊,因為mybaits的二級快取區域以mapper為單位劃分,當一個商品資訊變化會將所有商品資訊的快取資料全部清空。解決此類問題需要在業務層根據需求對資料有針對性快取。