文件名ehcache.xml放置於classpath根目錄(src/main/resources)。
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="1000"
overflowToDisk="true"
/>
<!-- 實體專用緩存:名稱必須=實體全限定名 -->
<cache name="com.sitechasia.occ.core.base.ExampleForTest"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="1000"
overflowToDisk="true"
/>
<!-- 查詢緩存必備區域 -->
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="7200"
overflowToDisk="true"/>
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="true"/>
</ehcache>
關鍵點:
1. 實體緩存名稱必須與實體全限定名完全一致,否則測試時拋出Cache is not alive異常。
2.UpdateTimestampsCache必須eternal="true",防止時間戳被淘汰導致查詢緩存永不過期。
3. 不建議依賴defaultCache,顯式配置每個實體/集合緩存區域。
<hibernate-mapping>
<class name="com.sitechasia.occ.core.base.ExampleForTest"
table="TESTTABLE" lazy="false">
<cache usage="read-write"/> <!-- 聲明二級緩存策略 -->
<id name="id" type="java.lang.String">
<column name="id" length="32"/>
<generator class="uuid"/>
</id>
<property name="field1" type="java.lang.String"/>
<property name="field2" type="java.lang.String"/>
</class>
</hibernate-mapping>
@Entity
@Table(name = "TESTTABLE")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) // 關鍵註解
public class ExampleForTest implements Serializable {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
@Column(name = "id", length = 32)
private String id;
@Column(name = "field1")
private String field1;
@Column(name = "field2")
private String field2;
// getter/setter省略
}
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
繼承AbstractTransactionalDataSourceSpringContextTests(Spring 2.5/3.x測試基類),事務自動回滾,數據隔離。
public class SecondLevelCacheTest extends AbstractTransactionalDataSourceSpringContextTests {
@Autowired
private SessionFactory sessionFactory;
@Test
public void testSecondLevelCache() {
// 1. 首次查詢:觸發SQL,填充二級緩存
Session s1 = sessionFactory.openSession();
ExampleForTest e1 = (ExampleForTest) s1.get(ExampleForTest.class, "known-id");
assertNotNull(e1);
s1.close();
// 2. 統計驗證:二級緩存命中數應為1
Statistics stats = sessionFactory.getStatistics();
stats.setStatisticsEnabled(true);
long cacheHitBefore = stats.getSecondLevelCacheHitCount();
// 3. 二次查詢:同一SessionFactory,不同Session
Session s2 = sessionFactory.openSession();
ExampleForTest e2 = (ExampleForTest) s2.get(ExampleForTest.class, "known-id");
assertNotNull(e2);
s2.close();
long cacheHitAfter = stats.getSecondLevelCacheHitCount();
assertEquals(1, cacheHitAfter - cacheHitBefore); // 驗證命中+1
}
@Test
public void testQueryCache() {
// 啟用查詢緩存
Query query = sessionFactory.getCurrentSession()
.createQuery("from ExampleForTest")
.setCacheable(true); // 關鍵!
List list1 = query.list(); // 首次查詢
Query query2 = sessionFactory.getCurrentSession()
.createQuery("from ExampleForTest")
.setCacheable(true);
List list2 = query2.list(); // 二次查詢
Statistics stats = sessionFactory.getStatistics();
stats.setStatisticsEnabled(true);
assertEquals(1, stats.getQueryCacheHitCount()); // 查詢緩存命中
}
}
| 異常/現象 | 根因 | 修正 |
|---|---|---|
org.hibernate.cache.CacheException: ... Cache is not alive | ehcache.xml中實體緩存name與實體全限定名不一致,或漏配實體緩存導致回退defaultCache(多實體共享defaultCache在事務測試中會被關閉) | ehcache.xml顯式配置<cache name="實體全限定名" .../> |
| 查詢緩存不生效(每次都執行SQL) | 1. 未設置setCacheable(true) 2. 實體未配置<cache/> 3. UpdateTimestampsCache配置錯誤 | 檢查三處配置,啟用Hibernate統計觀察QueryCacheHitCount |
| 數據不一致(讀到舊值) | 1. 緩存策略不當(read-only用於寫入實體) 2. 外部系統直接改庫未同步緩存 3. Class緩存TTL < Query緩存TTL導致1+N查詢讀到中間態 | 按業務選擇策略、外部寫入需手動evict、確保Class TTL ≥ Query TTL |
| 集合緩存順序錯誤 | 集合帶order-by,元素排序字段更新未觸發集合緩存失效 | 避免緩存帶排序集合,或更新排序字段後手動evictCollection |
applicationContext-test.xml配置dataSource、sessionFactory、transactionManager。@Rollback(true)(默認回滾),保證數據隔離。Hibernate 3二級緩存配置核心在於:實體緩存名稱精確匹配、UpdateTimestampsCache永久存活、Class緩存TTL不短於Query緩存、顯式聲明緩存策略。結合Spring測試框架與Hibernate Statistics API,可實現緩存行為的自動化驗證,將配置錯誤前移到測試階段發現。