這樣理解 MyBatis 緩存機制,真香!
為了提高數據訪問的性能,MyBatis 采用了一級緩存和二級緩存的緩存機制,那么它們是如何工作的?這篇文章,我們將詳細介紹這兩種緩存機制及其工作原理、配置方式和使用場景。
首先,看一張原理圖:
接著,我們來詳細地分析它們。
一、一級緩存
一級緩存(也叫本地緩存)是 MyBatis 默認開啟的,是基于 SqlSession 級別的緩存。也就是說,在同一個 SqlSession 中,對于相同的查詢,如果參數相同,MyBatis 會從一級緩存中直接獲取數據,而不會再去執行數據庫查詢。
1. 特點
作用范圍:同一個SqlSession 實例。
默認開啟:無需額外配置。
清空時機:
- 執行insert、update、delete 操作時,一級緩存會被清空。
- 調用SqlSession.clearCache() 方法手動清空。
2. 工作原理
當使用同一個SqlSession 執行相同的 SQL 查詢時,MyBatis 會先檢查一級緩存是否存在對應的查詢結果。如果存在,則直接返回緩存中的結果;如果不存在,則執行數據庫查詢并將結果放入一級緩存。
使用示例:
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1); // 查詢數據庫,結果存入一級緩存
User user2 = mapper.getUserById(1); // 從一級緩存中獲取結果
// user1 和 user2 指向同一個對象
}
二、二級緩存(全局緩存)
二級緩存是基于 namespace(通常對應于 Mapper 接口)的緩存,作用范圍超出了SqlSession,同一個 mapper 的多個SqlSession 共享一級緩存之外的緩存。二級緩存需要顯式開啟和配置。
1. 特點
作用范圍:同一個 Mapper 的所有SqlSession 實例。
默認關閉:需要在配置文件中手動開啟。
緩存實現:需要配置緩存實現類,如 MyBatis 自帶的緩存或第三方緩存(例如 Ehcache、Redis)。
序列化:二級緩存中的對象需要序列化,以支持跨SqlSession 共享。
2. 啟用步驟
(1) 全局配置:在全局配置文件mybatis-config.xml 中開啟二級緩存。
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
...
</configuration>
(2) Mapper 配置:在每個需要使用二級緩存的 Mapper XML 文件中配置<cache> 標簽。
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
<!-- SQL 語句定義 -->
</mapper>
或者使用自定義緩存實現:
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
(3) 映射接口注解:可以通過注解方式配置緩存(適用于 MyBatis 3.2 及以上版本)。
@CacheNamespace
public interface UserMapper {
// 方法定義
}
3. 緩存清理策略
MyBatis 二級緩存使用的是基于讀寫的緩存策略,當涉及數據修改操作(insert、update、delete)時,會清理相關 Mapper 的二級緩存,以保證數據一致性。
使用示例:
// 第一個 SqlSession
try (SqlSession session1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.getUserById(1); // 查詢數據庫,結果存入一級和二級緩存
session1.commit();
}
// 第二個 SqlSession
try (SqlSession session2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.getUserById(1); // 從二級緩存中獲取結果
}
三、緩存的高級配置
1. 緩存刷新策略
可以通過<cache> 標簽的屬性來配置緩存的刷新策略,如:
- eviction:指定緩存的清理策略(默認 LRU 策略)。
- flushInterval:指定緩存刷新時間間隔(單位:毫秒)。
- size:指定緩存的大小。
- readOnly:指定緩存是否為只讀。
示例:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
2. 使用第三方緩存
MyBatis 支持集成多種第三方緩存,如 Ehcache、Redis、Hazelcast 等。以 Ehcache 為例,配置步驟如下:
(1) 添加依賴:
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
(2) 配置 Mapper:
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
(3) 配置 Ehcache:
創建ehcache.xml 文件,配置緩存策略。
<ehcache>
<cache name="com.example.mapper.UserMapper"
maxEntriesLocalHeap="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"/>
</ehcache>
四、緩存使用注意事項
數據一致性:使用二級緩存時,需要確保緩存與數據庫的數據一致性,特別是在分布式環境下,推薦使用分布式緩存解決方案。
對象可序列化:二級緩存中的對象需要實現Serializable 接口,以支持緩存的序列化和反序列化。
避免緩存穿透:對高頻率的查詢,可以適當配置緩存,從而減少數據庫的壓力。
緩存命中率:合理設計查詢語句和緩存策略,提升緩存的命中率,優化性能。
五、總結
本文,我們詳細地介紹了 MyBatis 的緩存策略,包括一級緩存適用于單次請求中的重復查詢,而二級緩存適用于跨請求的共享緩存。在實際應用中,應根據具體業務需求和系統架構,選擇合適的緩存策略和實現方式,以達到最佳的性能優化效果。