MyBatis一級緩存與二級緩存原理與作用分析
緩存的作用
在 Web 系統(tǒng)中,最重要的操作就是查詢數(shù)據(jù)庫中的數(shù)據(jù)。但是有些時候查詢數(shù)據(jù)的頻率非常高,這是很耗費數(shù)據(jù)庫資源的,往往會導致數(shù)據(jù)庫查詢效率極低,影響客戶的操作體驗。于是可以將一些變動不大且訪問頻率高的數(shù)據(jù),放置在一個緩存容器中,用戶下一次查詢時就從緩存容器中獲取結果。
MyBatis 的緩存結構
MyBatis 系統(tǒng)中默認定義了兩級緩存:一級緩存和二級緩存:
MyBatis 一級緩存是一個 SqlSession 級別,Sqlsession 只能訪問自己的一級緩存的數(shù)據(jù)。
二級緩存是跨 sqlSession,是 mapper 級別的緩存,對于 mapper 級別的緩存不同的 sqlsession 是可以共享的。
MyBatis 默認開啟一級緩存,同時為了增強擴展性,MyBatis 定義了緩存接口 Cache,可以通過 Cache 自定義二級緩存。
一級緩存
MyBatis 一級緩存是一個 SqlSession 級別的緩存,緩存的執(zhí)行遵循下方的規(guī)則:
- 映射語句文件中的所有 select 語句的結果將會被緩存。
- 映射語句文件中的所有 insert、update 和 delete 語句會刷新緩存。
- 緩存默認會使用最近最少使用算法(LRU, Least Recently Used)算法來清除不需要的緩存。
- 緩存不會定時進行刷新(也就是說,沒有刷新間隔)。
- 緩存會保存列表或對象(無論查詢方法返回哪種)的 1024 個引用。
- 緩存會被視為讀/寫緩存,這意味著獲取到的對象并不是共享的,可以安全地被調用者修改,而不干擾其他調用者或線程所做的潛在修改。
接下來通過代碼模擬一級緩存的執(zhí)行,用的代碼是最簡單的一個用戶類,首先第一步在 mybatis-config 中開啟 log 日志:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
編寫測試代碼,在同樣的查詢條件下查詢第二次:
public class CacheTest1 {
public static void main(String[] args) {
// 獲取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 執(zhí)行Sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(1);
System.out.println(user);
//同樣的條件查詢第二次
User user2=mapper.getUserById(1);
System.out.println(user2);
sqlSession.close();
}
}

首先這段代碼是在一個 SqlSession 下,因此默認開啟了一級緩存,在結果中可以看到,第一次查詢走的是數(shù)據(jù)庫,第二次就不需要再查數(shù)據(jù)庫了。滿足第一條規(guī)則:
映射語句文件中的所有 select 語句的結果將會被緩存。
修改條件,在查詢第二次之前先往表里插入一條數(shù)據(jù):
public class CacheTest2 {
public static void main(String[] args) {
// 獲取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 執(zhí)行Sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(1);
System.out.println(user);
//第二次查詢前先插入一條數(shù)據(jù)
User user1=new User(5,"java");
mapper.insertUser(user1);
//同樣的條件查詢第二次
User user2=mapper.getUserById(2);
System.out.println(user2);
sqlSession.close();
}
}
在第一次查詢之后插入了一條數(shù)據(jù),第二次同樣條件查詢時沒有走緩存,再次查表,符合規(guī)則:
映射語句文件中的所有 insert、update 和 delete 語句會刷新緩存。
二級緩存
二級緩存的作用域比一級緩存要更大,二級緩存是 mapper 級別的緩存,你也可以理解為他是一個 namespace 內的緩存。
開啟二級緩存需要幾個步驟:
1、 MyBatis 中開啟緩存需要首先在設置中開啟 cacheEnabled
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
cacheEnabled 默認也是開啟狀態(tài)。
2、 在 mapper.xml 中使用二級緩存
在 UserMapper.xml 文件的 mapper 節(jié)點下增加一行 , 這個 mapper 就開啟了二級緩存。
MyBatis 緩存要求對應的對象需要實現(xiàn)序列話,因此給 User 對象加上序列化
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private int id;
private String name;
public User(){}
public User(int id,String name){
this.id=id;
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "id:"+this.id+" name:"+this.name;
}
}編寫測試用例,下面這段代碼在第一次查詢結束后關閉了 SqlSession,接著重新生成一個 SqlSession 執(zhí)行第二次查詢,一級緩存就沒有用了,這樣的場景下就需要二級緩存。
public class CacheTest3 {
public static void main(String[] args) {
// 獲取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 執(zhí)行Sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(1);
System.out.println(user);
// 第一次查詢結束后關閉 SqlSession
sqlSession.close();
sqlSession = MyBatisUtils.getSqlSession();
// 執(zhí)行Sql
mapper = sqlSession.getMapper(UserMapper.class);
//同樣的條件查詢第二次
User user2=mapper.getUserById(1);
System.out.println(user2);
sqlSession.close();
}
}

使用 useCache 對具體某一個查詢設置不適用緩存:
<select id="getUserById" resultMap="UserMap" parameterType="int" useCache="false">
select id,name from user where id=#{id};
</select>
cache 標簽可以通過配置進行修改:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="false"/>
重點講一下清除策略(eviction):
- LRU – 最近最少使用:移除最長時間不被使用的對象。
- FIFO – 先進先出:按對象進入緩存的順序來移除它們。
- SOFT – 軟引用:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對象。
- WEAK – 弱引用:更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則移除對象。
這里主要了解 LRU 和 FIFO 即可,默認的清除策略是 LRU。
其他幾個屬性的配置如下:
flushInterval(刷新間隔)屬性可以被設置為任意的正整數(shù),設置的值應該是一個以毫秒為單位的合理時間量。 默認情況是不設置,也就是沒有刷新間隔,緩存僅僅會在調用語句時刷新。
size(引用數(shù)目)屬性可以被設置為任意正整數(shù),要注意欲緩存對象的大小和運行環(huán)境中可用的內存資源。默認值是 1024。
readOnly(只讀)屬性可以被設置為 true 或 false,默認為 false。只讀的緩存會給所有調用者返回緩存對象的相同實例, 因此這些對象不能被修改,這就提供了可觀的性能提升。而可讀寫的緩存會(通過序列化)返回緩存對象的拷貝,速度上會慢一些,但是更安全。
到此這篇關于MyBatis一級緩存與二級緩存原理與作用分析的文章就介紹到這了,更多相關Mybatis緩存內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot訪問web中的靜態(tài)資源的方式小結
這篇文章主要介紹了SpringBoot訪問web中的靜態(tài)資源的方式,本文給大家介紹了兩種方式,通過代碼示例和圖文講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下2024-10-10
SpringBoot配置Spring?Security的實現(xiàn)示例
本文主要介紹了SpringBoot配置Spring?Security的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-10-10

