分享

Hibernate二级缓存【转】新理解

 roydocs 2013-09-13

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

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

Cache Provider class Type Cluster Safe Query Cache Supported
Hashtable (not intended for production use) org.hibernate.cache.HashtableCacheProvider memory yes
EHCache org.hibernate.cache.EhCacheProvider memory, disk yes
OSCache org.hibernate.cache.OSCacheProvider memory, disk yes
SwarmCache org.hibernate.cache.SwarmCacheProvider clustered (ip multicast) yes (clustered invalidation)
JBoss TreeCache org.hibernate.cache.TreeCacheProvider clustered (ip multicast), transactional yes (replication) yes (clock sync req.)


EHCache是不支持集群的。

下面以EHCache为例说明二级缓存的配置和使用:
(1)将echache.xml文件拷贝到相应的目录下。
(2)开启二级缓存,修改hibernate.cfg.xml文件
<property name= "hibernate.cache.use_second_level_cache" > true </property>
(3)指定缓存产品提供商,修改hibernate.cfg.xml文件
<property name= "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 (必须)说明了缓存的策略: transactionalread-writenonstrict-read-writeread-only

(2)

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

(3)

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


如:         <cache usage= "read-only" />
    *在hibernate.cfg.xml文件中,采用<class-cache>标签
         <class-cache class= "com.Student" usage= "read-only" />
    
建议使用这种方法,因为这样就能知道整个项目中哪些实体使用了二级缓存,很一目发然。

这里usage 属性指明了缓存并发策略(cache concurrency strategy)
    *只读缓存(Strategy: read only)
     如果你的应用程序只需读取一个持久化类的实例,而无需对其修改, 那么就可以对其进行只读 缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。

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

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

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

没有一种缓存提供商能够支持上列的所有缓存并发策略。下表中列出了各种提供器、及其各自适用的并发策略。

Cache read-only nonstrict-read-write read-write transactional
Hashtable (not intended for production use) yes yes yes
EHCache yes yes yes
OSCache yes yes yes
SwarmCache yes yes
JBoss TreeCache yes yes



下面写了一个测试类,一个方法中两次开启session,查询同一条记录:
public void testLoad1 (){
    Session session = null ;
    try {
        session = HibernateUtils . getSession ();
        session . beginTransaction ();
           
        Student s = (Student )session . load (Student . class , 1 );
        System . out . println ("student.name=" + s. getName ());
           
        session . beginTransaction (). commit ();
    } catch (Exception e ){
        e . printStackTrace ();
        session . beginTransaction (). rollback ();
    }
    finally {
        HibernateUtils . closeSession (session );
    }
       
    try {
        session = HibernateUtils . getSession ();
        session . beginTransaction ();
           
        Student s = (Student )session . load (Student . class , 1 );
        System . out . println ("student.name=" + s. getName ());
           
        session . beginTransaction (). commit ();
    } catch (Exception e ){
        e . printStackTrace ();
        session . beginTransaction (). rollback ();
    }
    finally {
        HibernateUtils . closeSession (session );
    }
}

执行结果:
21:38:27,703 WARN CacheFactory:43 - read-only cache configured for mutable class: com.Student
21:38:27,718 WARN EhCacheProvider:86 - Could not find configuration [com.Student]; using defaults.
Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.classesid as classesid0_0_ from Student student0_ where student0_.id=?
student.name=aa
student.name=aa

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

对于二级缓存来说,在SessionFactory 中定义了许多方法, 清除缓存中实例、整个类、集合实例或者整个集合,来管理二级缓存。
sessionFactory . evict (Cat . class , catId ); //evict a particular Cat
sessionFactory . evict (Cat . class ); //evict all Cats
sessionFactory . evictCollection ("Cat.kittens" , catId ); //evict a particular collection of kittens
sessionFactory . evictCollection ("Cat.kittens" ); //evict all kitten collections

CacheMode 参数用于控制具体的Session如何与二级缓存进行交互。

  • CacheMode.NORMAL - 从二级缓存中读、写数据。

  • CacheMode.GET - 从二级缓存中读取数据,仅在数据更新时对二级缓存写数据。

  • CacheMode.PUT - 仅向二级缓存写数据,但不从二级缓存中读数据。

  • CacheMode.REFRESH - 仅向二级缓存写数据,但不从二级缓存中读数据。通过 hibernate.cache.use_minimal_puts 的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多