内部缓存 (session缓存,一级缓存,事务缓存)
通过一系列Map类型来维护缓存实例 若加载某个数据对象,Session会首先根据所要加载的数据类和ID从entitiesByKey的map中寻找,若查不到才转向数据库。
内部缓存一般hibernate自己维护,若手动干预。可:
1.session.evict,从map中清除特定的对象
2.session.clear 清空内部缓存。即清空map
二级缓存(包括应用级缓存(sessionfactory缓存)和分布式缓存)
查找数据顺序:一级-——二级——数据库
若满足以下条件可以使用二级缓存:
1、数据不会被第三方应用修改(防止数据跟数据库中的数据不一致)
2、数据大小在可接受范围
3、数据更新率低
4、同一数据被系统频繁使用
5、非关键性数据(关键性数据:金融帐户数据等。
hibernate 本身并没有提供二级缓存产品化实现,而是为第3方提供接口,
故可根据实际情况选择不同的第三方缓存实现(EHCache(hibernate默认的)、 OSCache、
JbossCache、 SwarmCache等),Oscache、EHCache无法实现分布式缓存,jbosscache(更新集群中每个节点的这个数据)、
SwarmCache(废除集群中其他节点的用到的这个数据)则可以
缓存同步策略:
1、read-olny 对于不会发生数据改变的
2、nostrict-read-write
非严格的可读写,对于并发同步要求不是很严格的数据采取的策略,且数据更新频率较低的(几个小时一次,或更长)
3、 read-write严格的可读可写
此种策略在应用中是使用比较多的
4、transactional
事务型,必须在jta事务环境中,若事务失败,连同缓冲池的数据一同回滚到事务开始之前的状态。用于关键性数据的缓存。(只有jbosscache支持事务缓存)
配置二级缓存(EhCache为例)
1、配置准备
1) 1、把ehcache-1.2.3.jar加入到当前应用的classpath中。
2) 2、在hibernate.cfg.xml文件中加入EhCache缓存插件的提供类。
<!--配置缓存插件 --> <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property> |
3) 3、挎贝ehcache.xml文件到类路径(项目工程的src目录下),这个文件在Hibernate安装目录的etc下。
配2、2、置配置步骤:
Hibernate允许在类和集合的粒度上设置第二级缓存。在映射文件中,<class>和<set>元素都有一个<cache>子元素,这个子元素用来配置二级缓存。
示例:以category(产品类别)和product(产品)的映射为例:
1) 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) 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 | 设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中 |
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果eternal
=
"
false
"
,超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put的元素超过500个时,如果overflowToDisk
=
"
true
"
,就会把缓存中的部分数据保存在硬盘上的临时文件里面。
首先需要配置hibernate.cache.use_query_cache = true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
< cache name = " net.sf.hibernate.cache.StandardQueryCache "
maxElementsInMemory = " 50 " eternal = " false " timeToIdleSeconds = " 3600 "
timeToLiveSeconds = " 7200 " overflowToDisk = " true " />
< cache name = " net.sf.hibernate.cache.UpdateTimestampsCache "
maxElementsInMemory = " 5000 " eternal = " true " overflowToDisk = " true " />
然后
query.setCacheable( true ); // 激活查询缓存
query.setCacheRegion( " myCacheRegion " ); // 指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
< cache name = " myCacheRegion " maxElementsInMemory = " 10 " eternal = " false " timeToIdleSeconds = " 3600 " timeToLiveSeconds = " 7200 " overflowToDisk = " true " />
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache