hibernate-缓存说明

本文整理了网上关于Hibernate二级缓存的几篇文章。


一般来讲ORM中的缓存分为以下几类

事务级缓存

  在当前事务范围内的数据缓存.就Hibernate来讲,事务级缓存是基于Session的生命周期实现的,每个Session内部会存在一个数据缓存,它随着 Session的创建而存在,随着Session的销毁而灭亡,因此也称为Session Level Cache.

应用级缓存

  在某个应用中或应用中某个独立数据库访问子集中的共享缓存,此缓存可由多个事务共享(数据库事务或应用事务),事务之间的缓存共享策略与应用的事务隔离机制密切相关.在Hibernate中,应用级缓存由SessionFactory实现,所有由一个SessionFactory创建的 Session实例共享此缓存,因此也称为SessionFactory Level Cache.由于共享,所以要注意并发的隔离。

分布式缓存

  在多个应用实例,多个JVM间共享的缓存策略.分布式缓存由多个应用级缓存实例组成,通过某种远程机制(RMI,JMS)实现各个缓存实例间的数据同步,任何一个实例的数据修改,将导致整个集群间的数据状态同步.


Hibernate的缓存策略

  Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载,属于多事务级别,要防止事务并发性。

缓存是以map的形式进行存储的(key-id,value-object)。

后文的重点是二级缓存,因为一级缓存主要被Hibernate自己管理。

一级缓存(Session)

   事务范围,每个事务(Session)都有单独的第一级缓存.

   一级缓存的管理:当应用程序调用Session的save()、update()、saveOrUpdate()、get()或load(),以及调用查询接口的 list()、iterate()--(用的是n+1次查询,先查id)或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。 Session为应用程序提供了两个管理缓存的方法: evict(Object obj):从缓存中清除参数指定的持久化对象。 clear():清空缓存中所有持久化对象,flush():使缓存与数据库同步。当查询相应的字段如(name),而不是对象时,不支持缓存。

二级缓存(SessionFactory)

  Hibernate的二级缓存策略的一般过程如下:

   1:条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL句查询数据库,一次获得所有的数据对象(这个问题要考虑,如果你查询十万条数据时,内存不是被占用)。

 2:把获得的所有数据对象根据ID放入到第二级缓存中。

 3: 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。

   4:删除、更新、增加数据的时候,同时更新缓存。

  Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query Cache


不适合使用二级缓存的情况

    1 经常被修改的数据

    2 财务数据,绝对不允许出现并发

    3 与其他应用共享的数据。


常用的二级缓存插件


组件

Provider类

类型

集群

查询缓存

Hashtable

org.hibernate.cache.HashtableCacheProvider

内存

不支持

支持

EHCache

org.hibernate.cache.EhCacheProvider

内存,硬盘

最新支持

支持

OSCache

org.hibernate.cache.OSCacheProvider

内存,硬盘

不支持

支持

SwarmCache

org.hibernate.cache.SwarmCacheProvider

集群

支持

不支持

JBoss TreeCache

org.hibernate.cache.TreeCacheProvider

集群

支持

支持

       Hibernate已经不再提供对JCS(Java Caching System)组件的支持了。


二级缓存的策略

       当多个并发的事务同时访问持久化层的缓存中的相同数据时,会引起并发问题,必须采用必要的事务隔离措施。       在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下4种类型的并发访问策略,每一种策略对应一种事务隔离级别。建议结合数据库知识理解这一点,或者看Here

●   只读缓存(read-only)

       如果应用程序需要读取一个持久化类的实例,但是并不打算修改它们,可以使用read-only缓存。这是最简单,也是实用性最好的策略。

对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。

●   读/写缓存(read-write)

       如果应用程序需要更新数据,可能read-write缓存比较合适。如果需要序列化事务隔离级别,那么就不能使用这种缓存策略。

对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。

●   不严格的读/写缓存(nonstrict-read-write)

       如果程序偶尔需要更新数据(也就是说,出现两个事务同时更新同一个条目的现象很不常见),也不需要十分严格的事务隔离,可能适用nonstrict-read-write缓存。

对于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。

●   事务缓存(transactional)

       transactional缓存策略提供了对全事务的缓存,仅仅在受管理环境中使用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。

       在上面所介绍的隔离级别中,事务型并发访问策略的隔离级别最高,然后依次是读/写型和不严格读写型,只读型的隔离级别最低。事务的隔离级别越高,并发性能就越低。

二级缓存的使用


配置准备:

1)把ehcache-1.2.3.jar加入到当前应用的classpath中。

2)在hibernate.cfg.xml文件中加入EhCache缓存插件的提供类。

 
 
  1. <!--配置缓存插件 -->
  2. <property name="hibernate.cache.provider_class">
  3. org.hibernate.cache.EhCacheProvider
  4. </property>

3)挎贝ehcache.xml文件到类路径(项目工程的src目录下),这个文件在Hibernate安装目录的etc下。

配置步骤:

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>

在Spring托管的Hibernate中使用二级缓存 1.在spring的配置文件中,hibernate部分加入 xml 代码 org.hibernate.cache.EhCacheProvider true 2.为HBM表设置cache策略 xml 代码 3.在DAO中,调用find方法查询之前,设置使用缓存 Java代码 getHibernateTemplate().setCacheQueries(true); 补充: 如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置 hibernate.cache.use_query_cache true 才行。


参考:

http://www.blogjava.net/supercrsky/articles/238580.html

http://blog.csdn.net/xo_zhang/article/details/8540775

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值