Hibernate 作為 JPA 標準最成熟的實現,其緩存機制早於 JPA 2.0 標準化,擁有更豐富的配置選項、第三方緩存提供商生態、以及細粒度的控制能力。本文系統梳理 Hibernate 一級/二級/查詢緩存架構、主流緩存提供商整合、Hibernate 3.5+ 新特性 (Infinispan)、以及生產環境調優實踐。
| 維度 | 一級緩存 (Session 級) | 二級緩存 (SessionFactory 級) |
|---|---|---|
| 生命週期 | Session 打開到關閉 (通常 = 請求/事務) | SessionFactory 存活期間 (應用級) |
| 作用域 | 線程私有、事務隔離 | 跨 Session、跨事務、集群可共享 |
| 存儲內容 | 實體實例、集合、代理對象 | 實體數據 (脫管狀態)、集合數據、時間戳 |
| 啟用方式 | 默認開啟,不可關閉 | 需顯式配置 hibernate.cache.use_second_level_cache=true |
| 並發策略 | 無 (單線程) | read-only / read-write / nonstrict-read-write / transactional |
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 或 Infinispan: org.hibernate.cache.infinispan.InfinispanRegionFactory -->
主流提供商對比 (2024 視角):
| 提供商 | Maven 坐標 | 特點 | 適用場景 |
|---|---|---|---|
| Ehcache 3.x | org.ehcache:ehcache | JSR-107 標準、堆外內存、持久化、集群 (Terracotta 商業版) | 單機/小集群、需堆外緩存、簡單部署 |
| Infinispan | org.infinispan:infinispan-hibernate-cache | 分布式/複製/失效模式、JGroups 通訊、事務支援、熱門 Key 偵測 | 大規模集群、高可用、跨數據中心 |
| Hazelcast | com.hazelcast:hazelcast-hibernate | 分布式 IMDG、原生 Kubernetes 發現、SQL 查詢、Jet 流處理 | 雲原生、Kubernetes、需計算下推 |
| Redis (Hibernate-Redis) | com.github.redis-cache:hibernate-redis | 集中式、高性能、成熟運維生態 | 已有 Redis 基礎設施、讀多寫少 |
| Caffeine (本地) | com.github.ben-manes.caffeine:caffeine | 極致單機性能、W-TinyLFU、無分布式能力 | 只讀/極少寫、單實例/側車模式 |
註解方式 (推薦):
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "user.region")
public class User { ... }
@OneToMany
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set orders;
XML 方式:
<class-cache usage="read-write" region="user.region"/>
<collection-cache collection="User.orders" usage="nonstrict-read-write"/>
四種並發策略選型指南:
READ_ONLY:參數表、字典、靜態配置 —— 最快、無鎖。READ_WRITE:寫較少、需強一致性 —— 寫時獲取獨佔鎖、支援事務。NONSTRICT_READ_WRITE:極少寫、允許臨時髒讀 —— 無鎖、性能接近 READ_ONLY。TRANSACTIONAL:JTA 環境、需 XA 事務語義 —— 僅 Infinispan/JBoss Cache 支援。<property name="hibernate.cache.use_query_cache">true</property>
// 代碼中
Query query = session.createQuery("from User u where u.city = :city");
query.setParameter("city", "Beijing");
query.setCacheable(true); // 關鍵:標記可緩存
query.setCacheRegion("user.byCity"); // 可選:自定義區域
List<User> list = query.list();
查詢緩存鍵 = [查詢 SQL + 參數值 + 實體類型],值 = 實體 ID 列表。實際實體數據從二級緩存獲取。
UpdateTimestampsCache 時間戳機制)。query.addSynchronizedEntityClass(User.class)。hibernate.javax.cache.provider + hibernate.javax.cache.uri 即可切換任意 JCache 實現 (Ehcache 3、Hazelcast、Infinispan、Caffeine 等),解耦 Hibernate 與具體提供商。hibernate.generate_statistics=true + JMX/Micrometer 導出命中率、失效率、區域大小,接入 Prometheus/Grafana 告警。| 維度 | 建議 | 驗證方式 |
|---|---|---|
| 命中率 | 實體緩存 > 90%,查詢緩存 > 70% (讀多寫少場景) | JMX Statistics / Micrometer hibernate.cache.hit.ratio |
| 區域大小 | 配置 maxEntriesLocalHeap、timeToLiveSeconds、timeToIdleSeconds 防止 OOM | Ehcache/Infinispan 管理控制台、Heap Dump 分析 |
| 失效風暴 | 批量寫入前 sessionFactory.getCache().evictQueryRegion() 主動失效,避免大量單條失效 | 慢查詢日誌、GC 日誌關聯 |
| 集群一致性 | 分布式緩存選 invalidation 模式 (而非 replication) 減少網絡廣播 | 網絡監控、緩存集群日誌 |
| 序列化 | 分布式緩存值需實現 Serializable,推薦 Protobuf/Kryo 替代 JDK 序列化 | 緩存值大小監控、反序列化耗時 |
@Cacheable (JPA) + @org.hibernate.annotations.Cache (Hibernate 策略/區域) 共存,查詢緩存用 Hibernate 原生 setCacheable(true)。Hibernate 緩存體系經過十餘年生產環境打磨,已成為 Java 持久層性能優化的「核武器」。關鍵在於:理解兩級緩存邊界、選對並發策略、克制啟用查詢緩存、引入分布式緩存時做好一致性與容量規劃、建立指標監控體系。JPA 2.0 提供了標準化基線,Hibernate 則在其上構建了豐富的擴展生態 —— 兩者非對立,而是「標準接口 + 實現增強」的最佳實踐關係。