hibernate 的缓存机制

  Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:

    • 内置缓存

  SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。

    • 外置缓存

      SessionFactory的外置缓存是一个可配置的插件。默认情况下并未启动。外置缓存的介质可以是内存或者硬盘。

一级缓存:

  一级缓存即session级别的缓存,亦即事务级别的缓存策略,这种缓存策略是Hibernate内置的,不可被拆卸的。

二级缓存:

  Hibernate的第二级缓存即SessionFactory的外置缓存,其同时也称为进程级缓存或集群范围内的缓存。hibernate的二级缓存是需要第三方支持的,hibernate默认的二级缓存插件为ehcache,由于二级缓存是进程级的可能出现多线程并发问题,需要设置缓存的并发策略。

  那什么样的数据时可以放到二级缓存中的呢,如下所示:

    • 修改频率低的数据;
    • 不是很重要的数据,允许偶尔出现并发的数据;
    • 不会被并发访问的数据;
    • 参考性的数据,只是展示或者用于其他方面;

  那么不适合存放到二级缓存中的数据就有:

    • 经常被修改的数据;
    • 绝对不允许出现并发的数据,比如财务型的数据;
    • 与其他应用共享的数据;

  我们可以通过配置hibernate的属性"hibernate.cache.region.factory_class"(hibernate4之后改用这个属性名来配置cacheProvider)来配置缓存的提供者CacheProvider。

  下面是不同cache车间的cacheProvider的提供者的说明

Cache(缓存插件名称) Provider Class(cacheProvider提供者) Type(支持缓存类型) Cluster Safe(集群安全) Query Cache Supported(是否支持查询缓存)
ConcurrentHashMap (only for testing purpose, in hibernate-testing module)(仅用于测试) org.hibernate.testing.cache.CachingRegionFactory
memory
  yes
EHCache org.hibernate.cache.ehcache.EhCacheRegionFactory memory, disk, transactional, clustered yes yes
Infinispan org.hibernate.cache.infinispan.InfinispanRegionFactory clustered (ip multicast), transactional yes (replication or invalidation) yes (clock sync req.)

  默认情况下,entity对象并没有别缓存到二级缓存中,但是如何你不想这样做的话,你可以在配置文件中设置属性 "javax.persistence.sharedCache.mode" 的值来覆盖这个设置,可以设置的值有以下几个值:

    • ENABLE_SELECTIVE (默认推荐的值): 所有的entity不被缓存,除非明确被标注为可被缓存。
    • DISABLE_SELECTIVE: 所有的entity被缓存,除非明确被标注为不可缓存。
    • ALL: 所有的entity被缓存,即使被标注为不可缓存。
    • NONE: 所有的entity不被缓存,即使被标注为不可缓存。这个选项只有在不启动二级缓存的情况下才有意义。

  我们可以通过在配置文件中通过设置属性 "hibernate.cache.default_cache_concurrency_strategy" 的值来设置全局的缓存策略,但是不推荐这样做,一般情况下我们通过注解 @org.hibernate.annotations.Cache 来根据情况设置不同的缓存策略。就像下面的设置:

//Definition of cache concurrency strategy via @Cache
@Entity
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Classroom implements Serializable{...}


//Caching collections using annotations
@OneToMany(mappedBy="school", cascade={CascadeType.REMOVE}, fetch=FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public Set<Classroom> getClassrooms() {
    return classrooms;
}

   下面我们来看一下hibernate为我们提供的四种不同的缓存策略:

  • read-only

    如果你的应用数据只是需要读而不需要更改,那么对于这个持久化的实例就可以使用这个缓存策略,这个缓存策略是最简单也是最好用的一种策略,即使在集群环境中也是很安全的。

  • read-write

    如果应用数据需要更改,那么这种策略是合适的。这种缓存策略不适合那种要求有严格的事务隔离级别的应用环境。如果现在你的应用的缓存是需要用在JTA的环境中的话,那么我们就必须配置属性"hibernate.transaction.manager_lookup_class"指向一个JTA TransactionManager。在其他的环境中,如果使用这个策略的话,要确保事务在调用完Session.close()或者是Session.disconnect()之后结束。如果你想在集群环境中使用这种缓存策略的话,那么我们引入的第三方缓存插件需要支持锁机制。hibernate内置的cache providers是不支持锁机制的。

  • nonstrict-read-write

    如果应用系统只是偶尔的更新数据(这种情况下就极不可能会出现两个事物同时试着来更新相同的数据),并且并不要求严格的事物隔离级别的话,那么这个缓存策略是合适的。如果现在你的应用的缓存是需要用在JTA的环境中的话,那么我们就必须配置属性"hibernate.transaction.manager_lookup_class"的值啦。在其他的环境中,如果使用这个策略的话,要确保事务在调用完Session.close()或者是Session.disconnect()之后结束。

  • transactional

    这个缓存策略提供对全事务缓存机制的支持,比如JBoss TreeCache。它只能被使用在JTA的环境中,而且还必须指定属性"hibernate.transaction.manager_lookup_class"的值。

 

   以下我们来看一下常用的缓存插件对以上缓存策略的支持程度如何:

Cache(缓存插件名称) read-only nonstrict-read-write read-write transactional
ConcurrentHashMap (仅测试时使用) yes yes yes  
EHCache yes yes yes yes
Infinispan yes     yes

 查询缓存(The Query Cache):

  被查询的集合也可以被缓存,但是这只适用于下次查询时还是使用相同的查询参数。你可以通过设置属性"hibernate.cache.use_query_cache"的值为true来启动查询缓存。

  你也可以通过调用方法来手动设置查询缓存,代码如下所示:

org.hibernate.Query.setCacheable(true);

 

------------------------------------

以上是参考了网上的一些数据以及Hibernate的英文资料整理出来的,如果有什么欠缺的地方,还请大家能指出来。我们来一起讨论讨论。共同进步吗。

posted on 2016-01-12 16:52  一路东逝  阅读(2446)  评论(0编辑  收藏  举报

导航