Hibernate二级缓存【转】新理解

二级缓存也称为进程级的缓存或SessionFactory级的缓存,二级缓存可以被所有的session共享。二级缓存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二级缓存。

二级缓存是由不同的提供商提供,默认情况下,Hibernate使用EHCache进行JVM级别的缓存。

缓存策略提供商如下表:
Hashtable (not intended for production use)org.hibernate.cache.HashtableCacheProvidermemory yes
EHCacheorg.hibernate.cache.EhCacheProvidermemory, disk yes
OSCacheorg.hibernate.cache.OSCacheProvidermemory, disk yes
SwarmCacheorg.hibernate.cache.SwarmCacheProviderclustered (ip multicast)yes (clustered invalidation)
JBoss TreeCacheorg.hibernate.cache.TreeCacheProviderclustered (ip multicast), transactionalyes (replication)yes (clock sync req.)

EHCache是不支持集群的。

下面以EHCache为例说明二级缓存的配置和使用:

(1)将echache.xml文件拷贝到相应的目录下。

(2)开启二级缓存,修改hibernate.cfg.xml文件

<propertyname="hibernate.cache.use_second_level_cache">true</property>

(3)指定缓存产品提供商,修改hibernate.cfg.xml文件

<propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

(4)指定哪些实体使用二级缓存(两种方法)

*在实体映射文件中采用<cache>标签

<cache

usage="transactional|read-write|nonstrict-read-write|read-only"(1)

region="RegionName"(2)

include="all|non-lazy"(3)

       />
(1)

usage(必须)说明了缓存的策略: transactional、 read-write、 nonstrict-read-write或 read-only。

(2)

region (可选, 默认为类或者集合的名字(class or collection role name)) 指定第二级缓存的区域名(name of the second level cache region)

(3)

include (可选,默认为 all) non-lazy 当属性级延迟抓取打开时, 标记为lazy="true"的实体的属性可能无法被缓存

如:<cacheusage="read-only"/>

*在hibernate.cfg.xml文件中,采用<class-cache>标签

<class-cacheclass="com.Student"usage="read-only"/>

建议使用这种方法,因为这样就能知道整个项目中哪些实体使用了二级缓存,很一目发然。

这里usage属性指明了缓存并发策略(cacheconcurrencystrategy)

*只读缓存(Strategy:readonly)

如果你的应用程序只需读取一个持久化类的实例,而无需对其修改,那么就可以对其进行只读缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。

*读/写缓存(Strategy:read/write)

如果应用程序需要更新数据,那么使用读/写缓存比较合适。如果应用程序要求“序列化事务”的隔离级别(serializabletransactionisolationlevel),那么就决不能使用这种缓存策略。如果在JTA环境中使用缓存,你必须指定hibernate.transaction.manager_lookup_class属性的值,通过它,Hibernate才能知道该应用程序中JTA的TransactionManager的具体策略。在其它环境中,你必须保证在Session.close()、或Session.disconnect()调用前,整个事务已经结束。如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate内置的缓存策略并不支持锁定功能。

<classname="eg.Cat"....>

<cacheusage="read-write"/>

....

<setname="kittens"...>

<cacheusage="read-write"/>

....

</set>

</class>

*非严格读/写缓存(Strategy:nonstrictread/write)

如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。如果在JTA环境中使用该策略,你必须为其指定hibernate.transaction.manager_lookup_class属性的值,在其它环境中,你必须保证在Session.close()、或Session.disconnect()调用前,整个事务已经结束。

*事务缓存(transactional)

Hibernate的事务缓存策略提供了全事务的缓存支持,例如对JBossTreeCache的支持。这样的缓存只能用于JTA环境中,你必须指定为其hibernate.transaction.manager_lookup_class属性。

没有一种缓存提供商能够支持上列的所有缓存并发策略。下表中列出了各种提供器、及其各自适用的并发策略。
Hashtable (not intended for production use)yesyesyes
EHCacheyesyesyes
OSCacheyesyesyes
SwarmCacheyesyes
JBoss TreeCacheyes yes

下面写了一个测试类,一个方法中两次开启session,查询同一条记录:

publicvoidtestLoad1(){

Sessionsession=null;

try{

session=HibernateUtils.getSession();

session.beginTransaction();

Students=(Student)session.load(Student.class,1);

System.out.println("student.name="+s.getName());

session.beginTransaction().commit();

}catch(Exceptione){

e.printStackTrace();

session.beginTransaction().rollback();

}

finally{

HibernateUtils.closeSession(session);

}

try{

session=HibernateUtils.getSession();

session.beginTransaction();

Students=(Student)session.load(Student.class,1);

System.out.println("student.name="+s.getName());

session.beginTransaction().commit();

}catch(Exceptione){

e.printStackTrace();

session.beginTransaction().rollback();

}

finally{

HibernateUtils.closeSession(session);

}

}

执行结果:

21:38:27,703WARNCacheFactory:43-read-onlycacheconfiguredformutableclass:com.Student

21:38:27,718WARNEhCacheProvider:86-Couldnotfindconfiguration[com.Student];usingdefaults.

Hibernate:selectstudent0_.idasid0_0_,student0_.nameasname0_0_,student0_.classesidasclassesid0_0_fromStudentstudent0_wherestudent0_.id=?

student.name=aa

student.name=aa

只查询一次数据库,在跨session的操作中,由于开启了二级缓存,第二次session查询时,只要在缓存中查询就行,不用再去查询数据库。

对于二级缓存来说,在

相关推荐