Hibernate 內建兩級快取機制:**一級快取 (Session 級)** 必然啟用、**二級快取 (SessionFactory 級)** 需顯式配置。正確使用二級快取能大幅降低資料庫存取、提升讀取效能。本文完整涵蓋:快取架構、並發策略選擇、EhCache 提供者配置、實體/集合映射、大量寫入快取管理。
一、快取架構對比
| 特性 | 一級快取 (Session) | 二級快取 (SessionFactory) |
| 生命週期 | 交易/請求範圍 | 應用程式全域 (跨 Session) |
| 共享範圍 | 單一 Session | 所有 Session 共享 |
| 儲存內容 | 實體物件實例 | 實體散裝資料 (脫離物件圖) |
| 可關閉 | 不可關閉 | 可選擇性啟用/關閉 |
| 序列化要求 | 不需要 | 實體需實作 Serializable |
二、一級快取管理:大量寫入避免 OOM
批次插入 10 萬筆資料時,Session 會快取所有實體導致 OutOfMemoryError。
解決方案:JDBC 批次 + 定期 flush/clear
<property name="hibernate.jdbc.batch_size">20</property>
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
for (int i = 0; i < 100000; i++) {
Student stu = new Student();
session.save(stu);
if (i % 20 == 0) { // 每 20 筆 (batch_size)
session.flush(); // 執行批次 INSERT
session.clear(); // 清空 Session 快取,釋放記憶體
}
}
tx.commit();
三、二級快取啟用步驟
- 選擇並發策略
- 配置快取提供者
- 實體/集合映射啟用快取
四、四大內建並發策略
| 策略 | 隔離級別 | 適用場景 | 備註 |
transaction | 可重複讀 | 受管環境 (JTA)、高讀低寫、極少更新 | JTA 環境專用 |
read-write | 讀已提交 (時間戳) | 高讀低寫、少量更新 | 最常用 |
nonstrict-read-write | 不保證一致性 | 極少更新、臟讀可接受 | 需設足夠過期時間 |
read-only | 不可變 | 永不變更的參考資料 | 效能最佳 |
五、快取提供者選擇
| 提供者 | 特性 | 支援查詢快取 | 叢集支援 |
| EhCache | 純 Java、記憶體/磁碟、配置豐富 | ✓ | ✗ (需 Terracotta) |
| OSCache | 豐富過期策略、JGroups 叢集 | ✓ | △ |
| SwarmCache | 叢集快取 (JGroups) | ✗ | ✓ |
| JBoss Cache | 叢集快取、TreeCache | ✗ | ✓ |
推薦:單機/簡單叢集用 EhCache,完整叢集用 JBoss Cache/Infinispan。
六、EhCache 完整配置
hibernate.cfg.xml
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
ehcache.xml (放在 classpath 根目錄)
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<!-- 實體專屬配置 -->
<cache name="com.example.entity.Student"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<!-- 集合專屬配置 -->
<cache name="com.example.entity.Group.students"
maxElementsInMemory="5000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
</ehcache>
屬性說明
maxElementsInMemory:記憶體最大物件數
eternal:true=永不過期 (忽略 TTL/TTI)
timeToIdleSeconds (TTI):閒置超過秒數淘汰
timeToLiveSeconds (TTL):建立後存活秒數淘汰
overflowToDisk:記憶體滿時溢寫磁碟
七、實體與集合映射啟用快取
Group.hbm.xml (一對多集合)
<class name="Group" table="t_group">
<set name="students" ...>
<cache usage="read-write"/> <!-- 快取集合 (僅學生 ID) -->
<key column="group_id"/>
<one-to-many class="Student"/>
</set>
</class>
Student.hbm.xml (實體快取)
<class name="Student" table="t_student">
<cache usage="read-write"/> <!-- 快取實體散裝屬性 -->
<id .../>
<property .../>
</class>
關鍵點
- 集合快取 (
<set>/<list> 上) 僅快取**關聯實體的 ID**
- 實體快取 (
<class> 上) 快取**完整散裝屬性**
- **兩者皆需配置** 才能完整避免資料庫查詢
八、查詢快取 (Query Cache)
<property name="hibernate.cache.use_query_cache">true</property>
Query query = session.createQuery("from Student where age > :age");
query.setParameter("age", 18);
query.setCacheable(true); // 啟用查詢快取
List<Student> list = query.list();
查詢快取儲存:**查詢參數 + 實體 ID 列表**,需配合實體快取使用。
九、快取失效與同步策略
| 場景 | 處理方式 |
| 應用程式更新實體 | Hibernate 自動更新/失效對應快取項 |
| 外部系統直接修改資料庫 | 1. 縮短 TTL/TTI 2. 手動 sessionFactory.getCache().evictEntityRegion() 3. 資料庫觸發器通知 |
| 叢集環境 | 使用支援叢集的提供者 (JBoss Cache/Infinispan) + 快取失效廣播 |
十、監控與調優
- 啟用統計:
hibernate.generate_statistics=true
- 關鍵指標:
second_level_cache_hit_ratio (命中率)、second_level_cache_put_count、second_level_cache_miss_count
- 目標:讀多寫少實體命中率 > 90%
- 上一篇文章: jBPM 4 與 Spring 整合的兩種方式完整指南
- 下一篇文章: jBPM 4 與 Spring 整合架構深度解析:服務暴露、環境整合與交易統一
Copyright ©
程式碼之家 All Rights Reserved