Hibernate 快取機制全解析:Session 快取 vs SessionFactory 快取
快取位於應用程式與資料庫之間,以記憶體(或硬碟)儲存資料副本,降低資料庫存取頻率,提升效能。Hibernate 提供兩級快取架構:一級快取(Session 級)與 二級快取(SessionFactory 級),兩者在生命週期、範圍、併發策略上有本質差異。
核心概念對照表
| 特性 | 一級快取 (Session) | 二級快取 (SessionFactory) |
| 範圍 | 事務範圍 | 進程/叢集範圍 |
| 生命週期 | Session 開啟~關閉 | 應用程式整個生命週期 |
| 儲存內容 | 持久化物件實例(含 OID) | 物件鬆散資料、查詢結果集 |
| 必要性 | 內建、不可關閉 | 可選、需啟用外掛 |
| 併發問題 | 單執行緒無併發 | 多執行緒需隔離策略 |
一級快取(Session Cache)
- 又稱「事務範圍快取」,綁定於單一
Session(通常對應一個資料庫事務)。
- 同一
Session 內多次 get()/load() 同一 OID,只會發出一次 SQL,後續直接回傳快取物件。
- 不可關閉,也無法手動清除(可用
evict() 移除特定物件,clear() 清空)。
- 確保同一事務內物件唯一性(Identity Scope)。
二級快取架構
- 內建快取:儲存映射元資料、預定義 SQL,唯讀,無併發問題。
- 外掛快取(真正意義的二級快取):可配置第三方實作(Ehcache、Infinispan、Redis 等),儲存實體資料副本,支援叢集。
二級快取併發存取策略
| 策略 | 隔離級別 | 適用場景 |
| Transactional | Repeatable Read | 常讀少寫、受管環境(JTA) |
| Read-Write | Read Committed | 常讀少寫、非叢集 |
| Nonstrict-Read-Write | 無保證 | 極少修改、容許髒讀、需設定過期時間 |
| Read-Only | 最低 | 參考資料、從不修改 |
什麼資料適合放入二級快取?
- ✅ 很少修改的資料(郵遞區號、字典表)
- ✅ 不重要、允許偶爾併發問題的資料
- ✅ 不會被併發存取的資料
- ✅ 參考資料(唯讀)
不適合的資料
- ❌ 經常修改的資料
- ❌ 財務資料、絕對禁止併發
- ❌ 與其他應用共享的資料
二級快取運作流程
- 條件查詢 → 發出
SELECT * FROM table WHERE ... 取得所有欄位 → 依 ID 放入二級快取。
- 依 ID 存取 → 先查一級 → 再查二級 → 最後查 DB → 結果放入快取。
- 異動(增刪改)時同步更新快取。
- 注意:二級快取僅對「依 ID 查詢」有效,條件查詢需額外啟用 Query Cache。
Query Cache 運作原理
- 依 SQL、參數、分頁資訊組成
QueryKey。
- 以
QueryKey 查詢快取,命中則回傳 ID 列表,再由二級快取解析實體。
- 相關資料表異動時,對應
QueryKey 自動失效。
最佳實務建議
- 預設啟用一級快取,善用
Session 範圍減少重複查詢。
- 二級快取僅針對「讀多寫少、資料穩定」的實體啟用(
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE))。
- 謹慎啟用 Query Cache,需搭配二級快取,且會增加失效維護成本。
- 叢集環境選用支援分散式的快取實作(Infinispan、Redis),並正確配置併發策略。