Hibernater 的二级缓存是一个插件,下面是几种常用的缓存插件:
l EhCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。
l OSCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。
l SwarmCache:可作为群集范围内的缓存,但不支持Hibernate的查询缓存。
l JBossCache:可作为群集范围内的缓存,支持事务型并发访问策略,对Hibernate的查询缓存提供了支持。
2.3.5. 配置二级缓存的主要步骤:
1) 选择需要使用二级缓存的持久化类,设置它的命名缓存的并发访问策略。这是最值得认真考虑的步骤。
2) 选择合适的缓存插件,然后编辑该插件的配置文件。
2.4. 使用EhCache配置二级缓存:
2.4.1. 配置准备:
1) 把ehcache-1.2.3.jar加入到当前应用的classpath中。
2) 在hibernate.cfg.xml文件中加入EhCache缓存插件的提供类。
< !--配置缓存插件 -->
< property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
< /property>
3) 挎贝ehcache.xml文件到类路径(项目工程的src目录下),这个文件在Hibernate安装目录的etc下。
2.4.2. 配置步骤:
Hibernate允许在类和集合的粒度上设置第二级缓存。在映射文件中,< class>和< set>元素都有一个< cache>子元素,这个子元素用来配置二级缓存。
示例:以category(产品类别)和product(产品)的映射为例:
1) 修改要配置缓存的那个持久化类的对象关系映射文件:
Category.hbm.xml
< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
< hibernate-mapping>
< class name="org.qiujy.domain.cachedemo.Category" table="categories">
< !?
配置缓存,必须紧跟在class元素后面
对缓存中的Category对象采用读写型的并发访问策略
-->
< cache usage="read-write"/>
< id name="id" type="java.lang.Long">
< column name="id" />
< generator class="native" />
< /id>
< !-- 配置版本号,必须紧跟在id元素后面 -->
< version name="version" column="version" type="java.lang.Long" />
< property name="name" type="java.lang.String">
< column name="name" length="32" not-null="true"/>
< /property>
< property name="description" type="java.lang.String">
< column name="description" length="255"/>
< /property>
< set name="products" table="products" cascade="all" inverse="true">
< !-- Hibernate只会缓存对象的简单属性的值,
要缓存集合属性,必须在集合元素中也加入< cache>子元素
而Hibernate仅仅是把与当前持久对象关联的对象的OID存放到缓存中。
如果希望把整个关联的对象的所有数据都存入缓存,
则要在相应关联的对象的映射文件中配置< cache>元素
-->
< cache usage="read-write"/>
< key column="categoryId" not-null="true"/>
< one-to-many class="org.qiujy.domain.cachedemo.Product"/>
< /set>
< /class>
< /hibernate-mapping>
Product.hbm.xml
< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
< hibernate-mapping>
< class name="org.qiujy.domain.cachedemo.Product" table="products">
< cache usage="read-write"/>
< id name="id" type="java.lang.Long">
< column name="id" />
< generator class="native" />
< /id>
< !-- 配置版本号,必须紧跟在id元素后面 -->
< version name="version" column="version" type="java.lang.Long" />
< property name="name" type="java.lang.String">
< column name="name" length="32" not-null="true"/>
< /property>
< property name="description" type="java.lang.String">
< column name="description" length="255"/>
< /property>
< property name="unitCost" type="java.lang.Double">
< column name="unitCost" />
< /property>
< property name="pubTime" type="java.util.Date">
< column name="pubTime" not-null="true" />
< /property>
< many-to-one name="category"
column="categoryId"
class="org.qiujy.domain.cachedemo.Category"
cascade="save-update"
not-null="true">
< /many-to-one>
< /class>
< /hibernate-mapping>
2) 编辑ehcache.xml文件:
< ehcache>
< diskStore path="c:\\ehcache\"/>
< defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
< !-- 设置Category类的缓存的数据过期策略 -->
< cache name="org.qiujy.domain.cachedemo.Category"
maxElementsInMemory="100"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
< !-- 设置Category类的products集合的缓存的数据过期策略 -->
< cache name="org.qiujy.domain.cachedemo.Category.products"
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
< cache name="org.qiujy.domain.cachedemo.Product"
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
< /ehcache>
配置的元素说明:
元素或属性 描述
< diskStore> 设置缓存数据文件的存放目录
< defaultCache> 设置缓存的默认数据过期策略
< cache> 设定具体的命名缓存的数据过期策略
每个命名缓存代表一个缓存区域,每个缓存区域有各自的数据过期策略。命名缓存机制使得用户能够在每个类以及类的每个集合的粒度上设置数据过期策略。
cache元素的属性
name 设置缓存的名字,它的取值为类的全限定名或类的集合的名字
maxInMemory 设置基于内存的缓存中可存放的对象最大数目
eternal 设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds和timeToLiveSeconds属性;
默认值是false
timeToIdleSeconds 设置对象空闲最长时间,超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。
如果此值为0,表示对象可以无限期地处于空闲状态。
timeToLiveSeconds 设置对象生存最长时间,超过这个时间,对象过期。
如果此值为0,表示对象可以无限期地存在于缓存中。
overflowToDisk 设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
3) 写一测试类:
package org.qiujy.test.cache;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.qiujy.common.HibernateSessionFactory;
import org.qiujy.domain.cachedemo.Product;
public class TestCache {
public static void main(String[] args) {
//test cache.........
Session session2 = HibernateSessionFactory.getSession();
Transaction tx2 =null;
try{
tx2 = session2.beginTransaction();
List list = session2.createQuery("from Product").list();
for(int i = 0 ; i < list.size(); i++){
Product prod = (Product)list.get(i);
System.out.println(prod.getName());
}
tx2.commit();
}catch(HibernateException e){
if(tx2 != null){
tx2.rollback();
}
e.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
//-------------------
Session session3 = HibernateSessionFactory.getSession();
Transaction tx3 =null;
try{
tx3 = session3.beginTransaction();
Product prod = (Product)session3.get(Product.class, new Long(1));
System.out.println("从cache中得到,不执行SQL---" + prod.getName());
tx3.commit();
}catch(HibernateException e){
if(tx3 != null){
tx3.rollback();
}
e.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
}
}
首先数据库插入1000条产品记录和1条类别记录。此1000个产品都属于这一类别。然后执行以上测试类,在Session2中查询所有的产品,输出它的产品名,Session2会把这些数据加载到二级缓存中,由于有 1000个对象,而配置中定义内存中只能存放500个,剩下的对象就会写到指定的磁盘目录中缓存起来。所以在磁盘相应位置可看到数据文件:
2.5. 查询缓存(Query Cache):
对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把查询结果存放在第二缓存中。以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。
2.5.1. 查询缓存适用于以下场合:
l 在应用程序运行时经常使用的查询语句。
l 很少对与查询语句关联的数据库数据进行插入、删除或更新操作。
2.5.2. Hibernate的Query缓存策略的过程如下:
1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。
2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。
3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
只有当经常使用同样的参数进行查询时,这才会有些用处。
启用查询缓存的步骤:
1) 配置二级缓存:
Hibernate提供了三种和查询相关的缓存区域:
l 默认的查询缓存区域:org.hibernate.cache.StandardQueryCache
l 用户自定义的查询缓存区域:
l 时间戳缓存区域:org.hibernate.cache.UpdateTimestampCache
默认的查询缓存区域以及用户自定义的查询缓存区域都用于存放查询结果。而时间戳缓存区域存放了对与查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区域来判断被缓存的查询结果是否过期。所以,当应用程序对数据库的相关数据做了修改,Hibernate会自动刷新缓存的查询结果。但是如果其他应用程序对数据库的相关数据做了修改,则无法监测,此时必须由应用程序负责监测这一变化,然后手工刷新查询结果。Query接口的setForceCacheRefresh(true)可以手工刷新查询结果。
在ehcache.xml中添加如下配置:
< !-- 设置默认的查询缓存的数据过期策略 -->
< 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"/>
< !-- 设置自定义命名查询缓存customerQueries的数据过期策略 -->
< cache name="myCacheRegion"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
2) 打开查询缓存:在hibernate.cfg.xml添加如下配置
< !--启用查询缓存 -->
< property name="cache.use_query_cache">true< /property>
3) 在程序中使用:
虽然按以上设置好了查询缓存,但Hibernate在执行查询语句语句时仍不会启用查询缓存。对于希望启用查询缓存的查询语句,应该调用Query接口的setCacheeable(true)方法:
测试类如下:
package org.qiujy.test.cache;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.qiujy.common.HibernateSessionFactory;
import org.qiujy.domain.cachedemo.Product;
public class TessQueryCache {
public static void main(String[] args) {
Session session = HibernateSessionFactory.getSession();
Transaction tx =null;
try{
tx = session.beginTransaction();
Query query = session.createQuery("from Product");
//激活查询缓存
query.setCacheable(true);
//使用自定义的查询缓存区域,若不设置,则使用标准查询缓存区域
query.setCacheRegion("myCacheRegion");
List list = query.list();
for(int i = 0 ; i < list.size(); i++){
Product prod = (Product)list.get(i);
System.out.println(prod.getName());
}
tx.commit();
}catch(HibernateException e){
if(tx != null){
tx.rollback();
}
e.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
}
}
l EhCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。
l OSCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。
l SwarmCache:可作为群集范围内的缓存,但不支持Hibernate的查询缓存。
l JBossCache:可作为群集范围内的缓存,支持事务型并发访问策略,对Hibernate的查询缓存提供了支持。
2.3.5.
1)
2)
2.4.
2.4.1.
1)
2)
< !--配置缓存插件 -->
< property name="hibernate.cache.provider_class">
< /property>
3)
2.4.2.
Hibernate允许在类和集合的粒度上设置第二级缓存。在映射文件中,< class>和< set>元素都有一个< cache>子元素,这个子元素用来配置二级缓存。
示例:以category(产品类别)和product(产品)的映射为例:
1)
Category.hbm.xml
< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
< hibernate-mapping>
如果希望把整个关联的对象的所有数据都存入缓存,
则要在相应关联的对象的映射文件中配置< cache>元素
< /hibernate-mapping>
Product.hbm.xml
< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
< hibernate-mapping>
< /hibernate-mapping>
2)
< ehcache>
< /ehcache>
配置的元素说明:
元素或属性 描述
< diskStore> 设置缓存数据文件的存放目录
< defaultCache> 设置缓存的默认数据过期策略
< cache> 设定具体的命名缓存的数据过期策略
每个命名缓存代表一个缓存区域,每个缓存区域有各自的数据过期策略。命名缓存机制使得用户能够在每个类以及类的每个集合的粒度上设置数据过期策略。
cache元素的属性
name 设置缓存的名字,它的取值为类的全限定名或类的集合的名字
maxInMemory 设置基于内存的缓存中可存放的对象最大数目
eternal 设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds和timeToLiveSeconds属性;
默认值是false
timeToIdleSeconds 设置对象空闲最长时间,超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。
如果此值为0,表示对象可以无限期地处于空闲状态。
timeToLiveSeconds 设置对象生存最长时间,超过这个时间,对象过期。
如果此值为0,表示对象可以无限期地存在于缓存中。
overflowToDisk 设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
3)
package org.qiujy.test.cache;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.qiujy.common.HibernateSessionFactory;
import org.qiujy.domain.cachedemo.Product;
public class TestCache {
}
首先数据库插入1000条产品记录和1条类别记录。此1000个产品都属于这一类别。然后执行以上测试类,在Session2中查询所有的产品,输出它的产品名,Session2会把这些数据加载到二级缓存中,由于有 1000个对象,而配置中定义内存中只能存放500个,剩下的对象就会写到指定的磁盘目录中缓存起来。所以在磁盘相应位置可看到数据文件:
2.5.
对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把查询结果存放在第二缓存中。以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。
2.5.1.
l 在应用程序运行时经常使用的查询语句。
l 很少对与查询语句关联的数据库数据进行插入、删除或更新操作。
2.5.2.
1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。
2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。
3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
只有当经常使用同样的参数进行查询时,这才会有些用处。
启用查询缓存的步骤:
1)
Hibernate提供了三种和查询相关的缓存区域:
l 默认的查询缓存区域:org.hibernate.cache.StandardQueryCache
l 用户自定义的查询缓存区域:
l 时间戳缓存区域:org.hibernate.cache.UpdateTimestampCache
默认的查询缓存区域以及用户自定义的查询缓存区域都用于存放查询结果。而时间戳缓存区域存放了对与查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区域来判断被缓存的查询结果是否过期。所以,当应用程序对数据库的相关数据做了修改,Hibernate会自动刷新缓存的查询结果。但是如果其他应用程序对数据库的相关数据做了修改,则无法监测,此时必须由应用程序负责监测这一变化,然后手工刷新查询结果。Query接口的setForceCacheRefresh(true)可以手工刷新查询结果。
在ehcache.xml中添加如下配置:
< !-- 设置默认的查询缓存的数据过期策略 -->
2)
< !--启用查询缓存 -->
< property name="cache.use_query_cache">true< /property>
3)
虽然按以上设置好了查询缓存,但Hibernate在执行查询语句语句时仍不会启用查询缓存。对于希望启用查询缓存的查询语句,应该调用Query接口的setCacheeable(true)方法:
package org.qiujy.test.cache;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.qiujy.common.HibernateSessionFactory;
import org.qiujy.domain.cachedemo.Product;
public class TessQueryCache {
}