簡介

什麼是快取

**將一次查詢的結果暫存至記憶體,後續查詢只需查詢快取**

為什麼使用快取

**減少與資料庫的互動次數,減少系統開銷,提高系統效率**

什麼樣的資料能使用快取

**經常查詢且不常修改的資料**

Mybatis快取

一級快取

也叫本地快取,預設開啟,無法關閉,只在一次SqlSession中有效(拿到連線->關閉連線),底層由【Map】實現資料儲存

  • 與資料庫同一次會話期間查詢到的資料會放在本地快取中
  • 若之後需要獲取相同資料,直接從快取中獲取
    <select id="queryUserById" resultType="User">
SELECT * FROM user WHERE id = #{id};
</select> <update id="updateUser" parameterType="User">
UPDATE user set name = #{name}, pwd = #{pwd} WHERE id = #{id};
</update>
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
User user2 = mapper.queryUserById(1); System.out.println(user == user2);
sqlSession.close();
  • 日誌輸出SQL語句僅執行一次,且輸出結果為true,表明兩個user例項物件為同一個
sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1); User iris = new User(1, "Iris", "123");
mapper.updateUser(iris); User user2 = mapper.queryUserById(1);
System.out.println(user == user2);
  • 在修改資料庫資料(哪怕不是目標記錄)後再次查詢會重新訪問資料庫

【快取失效原因】

  • 查詢不同的記錄
  • 查詢不同的Mapper
  • 不同執行緒查詢
  • 增刪改操作均可能導致快取重新整理
  • 手動清除

二級快取

需在核心配置檔案中開啟快取【即使預設開啟】,才能手動配置快取屬性

開啟全域性快取(手動顯示開啟)

<setting name="cacheEnabled" value="true"/>

全域性快取,由於一級快取作用域太低從而產生,基於namespace級別的快取,二級快取會將每次會話的一次快取出儲存至二級快取,不同mapper所查詢的資料放在其對應快取【Map】中

二級快取由標籤cache實現,其中可設定相關屬性:

  • 快取策略

    • LRU【預設】:最近最少使用(移除最長時間不被使用的物件)
    • FIFO:先進先出(按物件進入快取的順序來移除它們)
    • SOFT:軟引用(基於垃圾回收器狀態和軟引用規則移除物件)
    • WEAK:弱引用(更積極地基於垃圾收集器狀態和弱引用規則移除物件)
  • 快取重新整理間隔(ms)
  • 引用數目【預設為1024個物件】
  • 是否僅可讀【預設可讀寫】

    下面的示例建立了一個FIFO快取,間隔60重新整理,最多儲存512個物件且返回的物件僅可讀
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>

測試二級快取是否有效

    SqlSession sqlSession = MybatisUtils.getSqlSession();
SqlSession sqlSession2 = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close(); User user2 = mapper2.queryUserById(1);
System.out.println(user2); System.out.println(user == user2);
sqlSession2.close();

【結果輸出:true】意為sqlSqssion2在sqlSession關閉後從二級快取中獲取到了sqlSession存入的資料。

報錯【物件未序列】的解決方法

  • 例項物件繼承Serializable

    public class User implements Serializable
  • 設定快取物件僅可讀(mapper.xml中)

    readOnly="true"

小結

  • 只要開啟二級快取,在相同Mapper下均有效
  • 所有資料都會先放在一級快取中
  • 只有當會話提交/關閉,資料才轉存至二級快取中

Mybatis快取原理