自 Hibernate 2.1 版本起,Ehcache 已成為 Hibernate 內建的預設二級緩存提供者(SessionFactory 層級)。在專案中針對性地引入緩存機制,能顯著提升系統效能,特別是對於頻繁讀取、較少變動的資料。
在 classpath 中加入以下 JAR 檔:
ehcache-core-xxx.jar (Ehcache 核心庫)commons-logging-xxx.jar (日誌介面)在 <session-factory> 標籤內新增下列屬性:
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="cache.use_second_level_cache">true</property>
<property name="cache.use_query_cache">true</property>
注意: 若未啟用 cache.use_second_level_cache (預設為 false),依據 ID 單筆查詢時將不會走二級緩存,導致產生大量重複 SQL。
使用 JPA 註解 @Cache 指定並發策略,Hibernate 提供五種策略供選擇:
| 策略 | 適用場景 |
|---|---|
NONE | 不啟用緩存 (預設) |
NONSTRICT_READ_WRITE | 資料極少更新 (數小時或更久) |
READ_ONLY | 資料絕不變更 (如字典表、設定檔) |
READ_WRITE | 基於時間戳判定,資料同步要求嚴格且讀寫頻繁 |
TRANSACTIONAL | 僅限 JTA 環境,基於事務邊界 |
範例:將實體標記為唯讀緩存
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class B {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String bname;
// getter/setter 略
}
置於 classpath 根目錄 (如 src/main/resources):
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="180"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
</ehcache>
關鍵屬性說明:
maxElementsInMemory:記憶體中最大物件數eternal:true 表示永不過期,將忽略 timeToIdleSeconds 等屬性overflowToDisk:記憶體不足時是否溢寫至磁碟timeToIdleSeconds:閒置超過秒數後淘汰timeToLiveSeconds:存活超過秒數後淘汰public static void getTest() {
Session session = HibernateSessionFactory.getSession();
Query q = session.createQuery("from B where id > ?");
q.setParameter(0, 10);
q.setCacheable(true); // 必須開啟查詢緩存
List list = q.list();
for (Object obj : list) {
B b = (B) obj;
System.out.print(b.getId() + "/");
}
session.close();
}
public static void main(String[] args) {
getTest(); // 第一次查詢,輸出 SQL
getTest(); // 第二次查詢,直接走緩存,無 SQL
}
控制台輸出:
Hibernate: select b0_.id as id1_, b0_.bname as bname1_ from B b0_ where b0_.id>?
11/14/18/25/26/27/28/29/
11/14/18/25/26/27/28/29/ <-- 第二次無 SQL,直接從緩存讀取
在 ehcache.xml 中定義專屬 <cache> 節點:
<cache name="cache_a"
maxElementsInMemory="5"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
查詢時指定區域:
Query q = session.createQuery("from B where id > ?");
q.setParameter(0, 10);
q.setCacheable(true);
q.setCacheRegion("cache_a"); // 使用自訂區域
預設磁碟路徑為 java.io.tmpdir,可透過 System.getProperty("java.io.tmpdir") 取得實際路徑 (如 C:\DOCUME~1\eric\LOCALS~1\Temp\)。
執行查詢並 Thread.sleep(10000) 等待磁碟寫入後,該目錄下將出現:
cache_a.data:自訂區域緩存資料com.eric.po.B.data:實體預設區域 (若未指定自訂區域)org.hibernate.cache.StandardQueryCache.data:查詢緩存資料org.hibernate.cache.UpdateTimestampsCache.data:時間戳緩存 (用於驗證緩存有效性)透過 @Cache 註解與 ehcache.xml 靈活配置,開發者可輕鬆在 Hibernate 中實現二級緩存與查詢緩存,並依業務特性選擇適當的並發策略,有效降低資料庫負載、提升回應速度。