<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<!-- 實體專用緩存建議顯式配置,名稱=實體全限定名 -->
<cache name="com.example.entity.User"
maxElementsInMemory="5000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"/>
<!-- 集合緩存示例 -->
<cache name="com.example.entity.User.roles"
maxElementsInMemory="2000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"/>
</ehcache>
<!-- hibernate.cfg.xml 或 Spring LocalSessionFactoryBean配置 -->
<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>
<!-- 可選:指定查詢緩存工廠 -->
<property name="hibernate.cache.query_cache_factory">org.hibernate.cache.StandardQueryCacheFactory</property>
<hibernate-mapping>
<class name="com.example.entity.User" table="SYS_USER">
<cache usage="read-write"/>
<id name="id"><generator class="native"/></id>
<property name="username"/>
<set name="roles" table="USER_ROLE">
<cache usage="read-write"/>
<key column="user_id"/>
<many-to-many class="com.example.entity.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>
// HQL查詢
Query query = session.createQuery("from User u where u.username like ?");
query.setParameter(0, "admin%");
query.setCacheable(true); // 關鍵!
query.setCacheRegion("userQueryRegion"); // 可選:使用自定義區域
List<User> list = query.list();
// Criteria查詢
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.like("username", "admin%"));
criteria.setCacheable(true); // 關鍵!
List<User> list2 = criteria.list();
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingDirectoryLocations">
<list><value>classpath:com/example/entity/</value></list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
public class CacheTest {
public static void main(String[] args) {
Session s = HibernateSessionFactory.getSession();
Criteria c = s.createCriteria(User.class);
c.setCacheable(true);
List<User> l1 = c.list();
User u1 = l1.get(0);
System.out.println("第一次查詢: " + u1.getUsername());
HibernateSessionFactory.closeSession();
try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }
s = HibernateSessionFactory.getSession();
c = s.createCriteria(User.class);
c.setCacheable(true);
List<User> l2 = c.list();
User u2 = l2.get(0);
System.out.println("第二次查詢: " + u2.getUsername());
// 控制台若無Hibernate SQL輸出,說明查詢緩存命中
HibernateSessionFactory.closeSession();
}
}
觀察控制台SQL輸出:第一次查詢有select ... from SYS_USER,第二次查詢無SQL輸出即代表查詢緩存命中(同時Class緩存也命中)。
| 方法 | 默認使用二級緩存 | 需額外配置 |
|---|---|---|
| session.load/get() | 是(Class緩存) | 無 |
| session.find/list/iterate() | 否 | setCacheable(true) + 實體配置<cache/> |
| Query.list/iterate() | 否 | setCacheable(true) + 實體配置<cache/> |
| Criteria.list() | 否 | setCacheable(true) + 實體配置<cache/> |
結論:只有load/get自動受益於Class緩存。所有列表查詢必須顯式setCacheable(true)才能使用查詢緩存,並依賴Class緩存組裝對象。
WEB-INF/classes或jar包根目錄。<cache name="..."/>必須等於實體全限定名(或集合角色名)。setCacheRegion("custom")時,ehcache.xml必須有同名<cache>定義。sessionFactory.getStatistics())監控命中率、內存佔用、淘汰率。