快取(Cache)就是資料交換的緩衝區,一個臨時儲存資料的地方,當我們讀取資料時會首先從快取中查詢需要的資料,如果找到了則直接執行,找不到的話再從記憶體中找。
在實際開發中,我們會經常對資料庫進行資料查詢,而從資料庫讀取資料的效率是非常低下的,並且頻繁地去存取資料庫會增巨量資料庫壓力降低資料庫查詢效能等,所以我們可以將經常查詢且不經常改變的資料儲存到快取中(快取就是記憶體中的一個物件),這樣使用者在查詢的時候就不用到資料庫中查詢(磁碟),從而減少與資料庫的交付次數,從而提高查詢效率,解決了高並行系統的效能問題。
快取的本質就是用空間換時間,犧牲資料的實時性,以伺服器記憶體中的資料暫時代替從資料庫讀取最新的資料,減少資料庫IO,減輕伺服器壓力,減少網路延遲,從而提高存取速度。
一級快取是SqlSession級別的快取,在運算元據庫時需要構造SqlSession物件,在物件中有一個 資料結構(HashMap) 用於儲存快取資料,不同的SqlSession之間的快取資料區域(HashMap)互不影響。
當在同一個sqlSession (對談) 中執行兩次相同的SQL語句時,第一次執行完畢會將從資料庫中查詢的資料寫到快取(記憶體),第二次查詢時會從快取中獲取資料,不再去底層資料庫查詢,從而提高查詢效率。需要注意的是,如果sqlSession執行了DML操作(insert、update、delete),並提交到資料庫,MyBatis則會清空sqlSession中的一級快取,這樣做的目的是為了保證快取中儲存的是最新的資訊,避免出現髒讀現象。
MyBatis預設開啟一級快取,不需要進行任何設定,當一個sqlSession結束後該sqlSession的一級快取也就不在了,一級快取是不能關閉的。
測試說明:
我們可以建立一張學生表,寫sql查詢語句根據id查詢學生資訊,定義一個方法,在方法內呼叫三次該查詢,提前開啟紀錄檔列印方便我們在控制檯檢視列印的sql語句,我們可以看到,只有第一次列印了sql語句也就是真正查詢了資料庫,後面的查詢使用了一級快取,直接在快取中讀取的資料並沒有存取資料庫。
我們接著對上面的資料進行測試,從上面我們可以知道學生表中的資料已經存入到快取中,接下來我們可以對資料進行(增/刪/改)測試(insert、update、delete),再進行查詢。可以發現進行了增、刪、改操作後控制檯列印了後面的查詢sql語句,也就是再次存取了資料庫進行查詢,所以清空了一級快取導致失效了。
我們繼續測試,這次我們開啟兩個SqlSession(對談),在SqlSession1中我們進行查詢操作從而開啟一級快取,在SqlSession2我們可以進行(增/刪/改)操作,再用SqlSession1去查詢,可以發現出現了髒資料,SqlSession1並沒有查詢到SqlSession2修改後的資料。所以驗證了一級快取只在資料庫對談內部共用
小結:
一級快取(本地快取), 作用域預設為sqlSession。當 Session flush 或 close 後, 該Session 中的所有Cache 將被清空。
本地快取不能被關閉, 但可以呼叫clearCache()來清空本地快取, 或者改變快取的作用域。
在mybatis3.1之後,可以設定本地快取的作用域,在 mybatis.xml 中設定。
讓一級快取失效的幾種情況:
① 不同的SqlSession對應不同的一級快取
② 同一個SqlSession但是查詢條件不同
③ 同一個SqlSession的兩次查詢期間執行了增刪改操作
④ 同一個SqlSession的兩次查詢期間手動清空了快取
二級快取也叫全域性快取,一級快取作用域太低了,二級快取預設是全域性開啟的,它是基於namespace級別的快取,一個名稱空間,對應一個二級快取,所以也稱之為「namespace快取」,需要在設定SQL語句的XML中新增節點, 以表示當前XML中的所有查詢都允許開通二級快取,並且,在節點上設定useCache=「true」,則對應的節點的查詢結果將被二級快取處理,並且,此查詢返回的結果的型別必須是實現了Serializable介面的,如果使用了設定如何封裝查詢結果,則必須使用節點來封裝主鍵的對映,滿足以上條件後,二級快取將可用,只要是當前namespace中查詢出來的結果,都會根據所執行的SQL語句及引數進行 結果的快取
開啟二級快取具體步驟:
在mybatis-config.xml檔案中開啟快取
<setting name="cacheEnabled"value="true"/>
<!-- 全域性設定引數,需要時再設定 -->
<settings>
<!-- 開啟二級快取 預設值為true -->
<setting name="cacheEnabled" value="true"/>
</settings>
在mapper.xml組態檔中使用二級快取
<!--在當前Mapper.xml檔案中使用二級快取-->
<mapper namespace="cn.hpu.mybatis.mapper.UserMapper">
<!-- 開啟本mapper namespace下的二級快取 -->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
<cache/>
也可以直接在mapper.xml檔案中加入,但是要記得實體類要序列化,不然容易會報Caused by: java.io.NotSerializableException: com.xsq.pojo.User異常
在實體類中實現序列化:
public class User implements Serializable {
//Serializable實現序列化,為了將來反序列化
}
工作機制
小結:
總結:
無論是一級快取還是二級快取,只要資料發生了寫操作(增、刪、改), 快取資料都將被自動清理
由於Mybatis的快取清理機制過於死板,所以,一般在開發實踐中並不怎麼使用!更多的是使用其它的快取工具並自行制定快取策略