目錄
1 MyBatis 緩存介紹
2 一級緩存
3 二級緩存
3.1 二級緩存介紹
3.2 二級緩存配置
3.3 二級緩存測試
4 參考文檔
1 MyBatis 緩存介紹
????????MyBatis 緩存是 MyBatis 中的一個重要特性,用于提高數據庫查詢的性能。MyBatis 提供了一級緩存和二級緩存兩種類型的緩存機制。
-
一級緩存:一級緩存(本地緩存)是 MyBatis 中默認的緩存機制,它是 SqlSession 級別的緩存。當使用 SqlSession 執行一次查詢時,查詢到的結果集會存儲在 SqlSession 的緩存中。當使用 SqlSession 再次執行相同的查詢時,它會首先從緩存中獲取結果,而不會再次查詢數據庫。一級緩存是基于事務的,當 SqlSession flush(插入、更新、修改)?或 close 后,該 SqlSession 中的所有 Cache 將被清空
-
二級緩存:二級緩存是 Mapper 級別的緩存,也稱為 namespace 級別。這意味著無論通過哪個 SqlSession 執行相同的 Mapper 接口操作,都可以訪問到相同的二級緩存數據,即跨 SqlSession 共享同一 Mapper 接口的數據。二級緩存需要手動配置,它可以實現更大范圍的數據共享和更高效的查詢性能。二級緩存也可以配置為使用不同的緩存實現,如 Ehcache、Redis 等
????????MyBatis 緩存的主要作用是減少對數據庫的訪問次數,提高查詢性能。然而,需要注意的是,緩存也會占用內存空間,如果緩存的數據量過大,可能會導致內存溢出的問題。因此,在使用 MyBatis 緩存時,需要根據具體的應用場景和數據量進行合理的配置和調優。
2 一級緩存
????????一級緩存 (local cache),即本地緩存,作用域默認為 SqlSession 。本地緩存不能被關閉,當 SqlSession flush(插入、更新、修改)?或 close 后,該 SqlSession 中的所有 Cache 將被清空。此外,也可以調用 sqlSession.clearCache()?來手動清空本地緩存。
????????在 MyBatis 配置文件中可以通過設置 localCacheScope 參數來改變一級緩存的作用域,它有以下兩種設置:
- SESSION:?當設置為 SESSION 時,一級緩存將對整個 SqlSession 有效。這意味著在同一個 SqlSession 中執行的查詢會共享同一個緩存。只有當執行 DML 語句(如插入、更新或刪除操作)時,緩存才會被清除。這可以有效地提高相同數據多次查詢的速度,但如果在多個 SqlSession 之間需要同步數據,或者有寫操作發生,可能會出現臟讀的情況
- STATEMENT:當設置為 STATEMENT 時,一級緩存僅對當前執行的語句有效。這意味著每次語句執行完畢后,緩存就會被清空。這種設置適用于那些可能需要避免臟讀風險的場景,因為它確保了每次查詢都是獨立的,不會受到其他查詢的影響
@Test
public void selectById1() {EmployeeMapper mapper = sqlSessionOne.getMapper(EmployeeMapper.class);// 第一次查詢System.out.println("第一次查詢");Employee employee1 = mapper.selectEmployeeById(1);System.out.println(employee1);// 第二次查詢System.out.println("第二次查詢");Employee employee2 = mapper.selectEmployeeById(1);System.out.println(employee2);// 手動清除本地緩存System.out.println("清除本地緩存");sqlSessionOne.clearCache();// 第三次查詢System.out.println("第三次查詢");Employee employee3 = mapper.selectEmployeeById(1);System.out.println(employee3);}
第一次查詢,從數據庫中查詢數據并將查詢結果保存在本地緩存中
第二次查詢,直接獲取本地緩存的查詢結果
清空本地緩存
第三次查詢,從數據庫中查詢數據
3 二級緩存
3.1 二級緩存介紹
????????MyBatis 的二級緩存是一個更為全局的緩存機制,其作用范圍是 namespace 級別,可以被多個 SqlSession 共享。它的生命周期與應用程序同步,主要用于解決一級緩存不能跨會話共享的問題。
以下是二級緩存的一些詳細介紹:
- 使用場景:二級緩存適用于多個 SqlSession 需要共享數據的場景。當開啟二級緩存后,MyBatis 會先從二級緩存中獲取數據,如果沒有找到,則會繼續查找一級緩存,最后才訪問數據庫
- 配置條件:要使用二級緩存,需要滿足以下條件:
- 全局性地開啟或關閉所有映射器配置文件中已配置的任何二級緩存,可以在 MyBatis 配置文件中通過設置 <setting name="cacheEnabled" value="true"> 來實現
- 在需要使用二級緩存的映射器配置文件(如 sqlMapper.xml)中添加 <cache/> 配置
- 使用二級緩存的實體類對象必須是可序列化的,即實現 java.io.Serializable 接口
- 工作機制:當 SqlSession 對象關閉或提交之后,一級緩存中的數據會被寫入到二級緩存當中。這樣,即使在不同的 SqlSession 之間,也可以訪問到相同的數據集,從而提高了數據訪問的效率
- 緩存策略:二級緩存的回收策略可以通過設置 <cache> 標簽的屬性來定義,例如 LRU(最近最少使用)策略,用于移除最長時間不被使用的對象
3.2 二級緩存配置
在 MyBatis 配置文件進行設置
<!--開啟二級緩存-->
<settings><setting name="cacheEnabled" value="true"/>
</settings>
在 SQL 映射文件中設置 <cache> 標簽
在 <cache> 標簽中,可以設置多種屬性來定義緩存的行為,例如:
- eviction:指定緩存回收策略,默認是 LRU(最近最少使用)
- LRU:最近最少使用:移除最長時間不被使用的對象
- FIFO:先進先出:按對象進入緩存的順序來移除它們
- SOFT:軟引用:移除基于垃圾回收器狀態和軟引用規則的對象
- WEAK:弱引用:更積極地移除基于垃圾收集器狀態和弱引用規則的對象
- flushInterval:設置緩存刷新間隔,單位為毫秒,默認不清空
- size:指定二級緩存可以存儲的最大對象數量,默認是 1024
- readOnly:標記緩存是否為只讀,默認為 false,即可讀可寫,這回慢一點,但是安全
- type:指定緩存的具體實現類型
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
注:在 Mapper 接口使用?@CacheNamespace 注解也可以開啟二級緩存
實體類實現 java.io.Serializable 接口
3.3 二級緩存測試
@Test
public void selectAll() {// 不同 sqlSession 對同一 mapper 接口進行操作SqlSession sqlSession1 = sqlSessionFactory.openSession();EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);SqlSession sqlSession2 = sqlSessionFactory.openSession();EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);// 通過 sqlSession1 進行第一次查詢List<Employee> employees1 = mapper1.selectAllEmployee();for (Employee employee : employees1) {System.out.println(employee);}// 當 sqlsession 提交、關閉時,二級緩存會有數據//sqlSession1.commit();sqlSession1.clearCache();sqlSession1.close();// 通過 sqlSession2 進行第二次查詢List<Employee> employees2 = mapper2.selectAllEmployee();for (Employee employee : employees2) {System.out.println(employee);}
}
通過 sqlSession1 進行第一次查詢,二級緩存沒有數據
清空 sqlSession1 的一級緩存
sqlSession1 關閉(二級緩存有查詢結果,二級緩存的數據是從一級緩存中來的嗎???)
通過 sqlSession2?進行第二次查詢,從二級緩存中獲得查詢結果,二級緩存命中率 0.5
補充:
禁用二級緩存
????????可以使用 useCache 屬性(這個屬性只有 select 有)來禁用二級緩存,默認為 true,即使用二級緩存,當然也可以通過?@Options(useCache=true) 來設置。
清空一級和二級緩存
????????flushCache 屬性是用來清空一級緩存和二級緩存的。select 中默認為 flushCache=false,insert、delete、update 中默認為 flushCache=true,因為執行數據的增刪改 SQL 語句后,數據庫與緩存數據可能已經不一致,此時緩存已經不能用了,如果不清空緩存則可能出現臟讀的情況。也可以通過?@Options(flushCache=options.FlushCachePolicy.TRUE)?進行設置。
也可以通過實現 cache 接口自定義二級緩存
4 參考文檔
尚硅谷文檔
mybatis 中文文檔 – MyBatis 3 | XML 映射器
Mybatis3詳解(十二)----Mybatis緩存 - 唐浩榮 - 博客園 (cnblogs.com)