Hibernate 缓存机制

缓存是位于应用程序与物理数据源之间,用于临时存放复制数据的内存区域,目的是为了减少应用程序对物理数据源访问的次数,从而提高应用程序的运行性能. 
  Hibernate在查询数据时,首先到缓存中去查找,如果找到就直接使用,找不到的时候就会从物理数据源中检索,所以,把频繁使用的数据加载到缓存区后,就可以大大减少应用程序对物理数据源的访问,使得程序的运行性能明显的提升.
 
  
Hibernate缓存分类: 

Session缓存,一级缓存. 

SessionFactory的缓存分为内置缓存和外置缓存.内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定义SQL语句等),对于应用程序来说,它是只读的.外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备. 

Hibernate的缓存范围 

Hibernate的一级缓存和二级缓存都位于均位于持久层,且均用于存放数据库数据的副本,最大的区别就是缓存的范围各不一样. 

缓存的范围分为3类: 

1.事务范围 
   事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围. 
2.应用范围 
   应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围. 
3.集群范围 
   在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致,缓存中的数据通常采用对象的松散数据形式. 

  Hibernate的缓存管理 

一级缓存的管理: 

  evit(Object obj)  将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象. 
  clear()  将一级缓存中的所有持久化对象清除,释放其占用的内存资源 
  contains(Object obj) 判断指定的对象是否存在于一级缓存中. 
  flush() 刷新一级缓存区的内容,使之与数据库数据保持同步. 

  二级缓存的管理: 
   
   evict(Class arg0, Serializable arg1)  将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源. 
  

Java代码    收藏代码
  1. sessionFactory.evict(Customer.classnew Integer(1));  


   evict(Class arg0)  将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源. 
  

Java代码    收藏代码
  1. sessionFactory.evict(Customer.class);  


   evictCollection(String arg0)  将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源. 
  

Java代码    收藏代码
  1. sessionFactory.evictCollection("Customer.orders");  



Hibernate的二级缓存的配置 

首先,不是所有的数据都适合放在二级缓存中,看一下,什么样的数据适合放在二级缓存中来?什么样的数据不适合放在二级缓存中来? 
  下面这几种情况就不适合加载到二级缓存中: 
  1.经常被修改的数据 
  2.绝对不允许出现并发访问的数据 
  3.与其他应用共享的数据 
  下面这己种情况合适加载到二级缓存中: 
  1.数据更新频率低 
  2.允许偶尔出现并发问题的非重要数据 
  3.不会被并发访问的数据 
  4.常量数据 
  5.不会被第三方修改的数据 

Hibernate的二级缓存功能是靠配置二级缓存插件来实现的,Hibernate为了集成这些插件,Hibernate提供了org.hibernate.cache.CacheProvider借口,它充当缓存插件与Hibernate之间的适配器 . 

常用的二级缓存插件 
EHCache  org.hibernate.cache.EhCacheProvider 
OSCache  org.hibernate.cache.OSCacheProvider 
SwarmCahe  org.hibernate.cache.SwarmCacheProvider 
JBossCache  org.hibernate.cache.TreeCacheProvider 

简单介绍一下EHCache的配置 
hibernate.cfg.xml 

Xml代码    收藏代码
  1. <hibernate-configuration>  
  2.    <session-factory>  
  3.       <!-- 设置二级缓存插件EHCache的Provider类-->  
  4.       <property name="hibernate.cache.provider_class">  
  5.          org.hibernate.cache.EhCacheProvider  
  6.       </property>  
  7.       <!-- 启动"查询缓存" -->  
  8.       <property name="hibernate.cache.use_query_cache">  
  9.          true  
  10.       </property>  
  11.    </session-factory>  
  12.  </hibernate-configuration>  



ehcache.xml 

Xml代码    收藏代码
  1. <ehcache>  
  2.   <!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 -->  
  3.   <diskStore path="java.io.tmpdir"/>  
  4.     <defaultCache maxElementsInMemory="10000" eternal="false"  timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>  
  5. </ehcache>  



****.hbm.xml 

Xml代码    收藏代码
  1. <?xml version="1.0" encoding='UTF-8'?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC  
  3.                             "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.                             "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >  
  5.   
  6. <hibernate-mapping>  
  7.        
  8.    <class>  
  9.        <!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->  
  10.        <cache usage="read-write"/>      
  11.    </class>  
  12.   
  13. </hibernate-mapping>  

 

 

上面源自:http://yuanyao.iteye.com/blog/249465

 

 

下面是官方的说法:

21.2. 二级缓存(The Second Level Cache)

Hibernate 的 Session 在事务级别进行持久化数据的缓存操作。 当然,也有可能分别为每个类(或集合),配置集群、或 JVM 级别(SessionFactory 级别)的缓存。你甚至可以为之插入一个集群的缓存。注意,缓存永远不知道其他应用程序对持久化仓库(数据库)可能进行的修改 (即使可以将缓存数据设定为定期失效)。

You have the option to tell Hibernate which caching implementation to use by specifying the name of a class that implements org.hibernate.cache.CacheProvider using the propertyhibernate.cache.provider_class. Hibernate is bundled with a number of built-in integrations with the open-source cache providers that are listed in 表 21.1 “缓存策略提供商(Cache Providers)”. You can also implement your own and plug it in as outlined above. Note that versions prior to Hibernate 3.2 use EhCache as the default cache provider.

表 21.1. 缓存策略提供商(Cache Providers)

CacheProvider classTypeCluster SafeQuery Cache Supported
Hashtable (not intended for production use)org.hibernate.cache.HashtableCacheProvidermemory yes
EHCacheorg.hibernate.cache.EhCacheProvidermemory, disk, transactional, clusteredyesyes
OSCacheorg.hibernate.cache.OSCacheProvidermemory,disk yes
SwarmCacheorg.hibernate.cache.SwarmCacheProviderclustered (ip multicast)yes (clustered invalidation) 
JBoss Cache 1.xorg.hibernate.cache.TreeCacheProviderclustered (ip multicast), transactionalyes (replication)yes (clock sync req.)
JBoss Cache 2org.hibernate.cache.jbc.JBossCacheRegionFactoryclustered (ip multicast), transactionalyes (replication or invalidation)yes (clock sync req.)

21.2.1. 缓存映射(Cache mappings)

As we have done in previous chapters we are looking at the two different possibiltites to configure caching. First configuration via annotations and then via Hibernate mapping files.

By default, entities are not part of the second level cache and we recommend you to stick to this setting. However, you can override this by setting the shared-cache-mode element in yourpersistence.xml file or by using the javax.persistence.sharedCache.mode property in your configuration. The following values are possible:

  • ENABLE_SELECTIVE (Default and recommended value): entities are not cached unless explicitly marked as cacheable.

  • DISABLE_SELECTIVE: entities are cached unless explicitly marked as not cacheable.

  • ALL: all entities are always cached even if marked as non cacheable.

  • NONE: no entity are cached even if marked as cacheable. This option can make sense to disable second-level cache altogether.

The cache concurrency strategy used by default can be set globaly via thehibernate.cache.default_cache_concurrency_strategy configuration property. The values for this property are:

  • read-only

  • read-write

  • nonstrict-read-write

  • transactional

注意

It is recommended to define the cache concurrency strategy per entity rather than using a global one. Use the @org.hibernate.annotations.Cache annotation for that.

例 21.5. Definition of cache concurrency strategy via @Cache

@Entity 
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }

Hibernate also let's you cache the content of a collection or the identifiers if the collection contains other entities. Use the @Cache annotation on the collection property.

例 21.6. Caching collections using annotations

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() {
    return tickets;
}

例 21.7 “@Cache annotation with attributes”shows the @org.hibernate.annotations.Cache annotations with its attributes. It allows you to define the caching strategy and region of a given second level cache.

例 21.7. @Cache annotation with attributes

@Cache(
    CacheConcurrencyStrategy usage();
    String region() default "";
    String include() default "all";
)

usage: the given cache concurrency strategy (NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)

region (optional): the cache region (default to the fqcn of the class or the fq role name of the collection)

include (optional): all to include all properties, non-lazy to only include non lazy properties (default all).


Let's now take a look at Hibernate mapping files. There the <cache> element of a class or collection mapping is used to configure the second level cache. Looking at 例 21.8 “The Hibernate <cache> mapping element” the parallels to anotations is obvious.

例 21.8. The Hibernate <cache> mapping element

<cache
    usage="transactional|read-write|nonstrict-read-write|read-only"
    region="RegionName"
    include="all|non-lazy"
/>

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

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

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


Alternatively to <cache>, you can use <class-cache> and <collection-cache> elements inhibernate.cfg.xml.

Let's now have a closer look at the different usage strategies

21.2.2. 策略:只读缓存(Strategy:read only)

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

21.2.3. 策略:读写/缓存(Strategy:read/write)

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

21.2.4. 策略:非严格读/写缓存(Strategy:nonstrict read/write)

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

21.2.5. 策略:事务缓存(transactional)

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

21.2.6. 各种缓存提供商/缓存并发策略的兼容性

重要

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

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

表 21.2. 各种缓存提供商对缓存并发策略的支持情况(Cache Concurrency Strategy Support)

Cacheread-onlynonstrict-read-writeread-writetransactional
Hashtable (not intended for production use)yesyesyes 
EHCacheyesyesyesyes
OSCacheyesyesyes 
SwarmCacheyesyes  
JBoss Cache 1.xyes  yes
JBoss Cache 2yes  yes

21.3. 管理缓存(Managing the caches)

无论何时,当你给 save()update() 或 saveOrUpdate() 方法传递一个对象时,或使用load()get()list()iterate() 或 scroll() 方法获得一个对象时,该对象都将被加入到 Session 的内部缓存中。

当随后 flush() 方法被调用时,对象的状态会和数据库取得同步。如果你不希望此同步操作发生,或者你正处理大量对象、需要对有效管理内存时,你可以调用 evict() 方法,从一级缓存中去掉这些对象及其集合。

例 21.9. Explcitly evicting a cached instance from the first level cache using Session.evict()

ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
while ( cats.next() ) {
    Cat cat = (Cat) cats.get(0);
    doSomethingWithACat(cat);
    sess.evict(cat);
}

Session 还提供了一个 contains() 方法,用来判断某个实例是否处于当前 session 的缓存中。

如若要把所有的对象从 session 缓存中彻底清除,则需要调用 Session.clear()

对于二级缓存来说,在 SessionFactory 中定义了许多方法,清除缓存中实例、整个类、集合实例或者整个集合。

例 21.10. Second-level cache eviction via SessionFactoty.evict() andSessionFacyory.evictCollection()

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 的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。

如若需要查看二级缓存或查询缓存区域的内容,你可以使用统计(Statistics) API。

例 21.11. Browsing the second-level cache entries via the Statistics API

Map cacheEntries = sessionFactory.getStatistics()
        .getSecondLevelCacheStatistics(regionName)
        .getEntries();

此时,你必须手工打开统计选项。可选的,你可以让 Hibernate 更人工可读的方式维护缓存内容。

例 21.12. Enabling Hibernate statistics

hibernate.generate_statistics true
hibernate.cache.use_structured_entries true

21.4. 查询缓存(The Query Cache)

查询的结果集也可以被缓存。只有当经常使用同样的参数进行查询时,这才会有些用处。

21.4.1. 启用查询缓存

按照应用程序的事务性处理过程,查询结果的缓存将产生一些负荷。例如,如果缓存针对 Person 的查询结果,在 Person 发生了修改时,Hibernate 将需要跟踪这些结果什么时候失效。因为大多数应用程序不会从缓存查询结果中受益,所以 Hibernate 在缺省情况下将禁用缓存。要使用查询缓存,你首先需要启用查询缓存:

hibernate.cache.use_query_cache true

这个设置创建了两个新的缓存 region:

  • org.hibernate.cache.StandardQueryCache,保存缓存的查询结果

  • org.hibernate.cache.UpdateTimestampsCache,保存对可查询表的最近更新的时间戳。它们用于检验查询结果。

重要

If you configure your underlying cache implementation to use expiry or timeouts is very important that the cache timeout of the underlying cache region for the UpdateTimestampsCache be set to a higher value than the timeouts of any of the query caches. In fact, we recommend that the the UpdateTimestampsCache region not be configured for expiry at all. Note, in particular, that an LRU cache expiry policy is never appropriate.

如上面所提及的,绝大多数的查询并不能从查询缓存中受益,所以 Hibernate 默认是不进行查询缓存的。如若需要进行缓存,请调用 org.hibernate.Query.setCacheable(true)方法。这个调用会让查询在执行过程中时先从缓存中查找结果,并将自己的结果集放到缓存中去。

注意

查询缓存不会缓存缓存中实际实体的状态;它只缓存标识符值和值类型的结果。出于这个原因,对于那些作为查询结果缓存的一部分(和集合缓存一样)进行缓存的实体,查询缓存应该和二级缓存一起使用。

21.4.2. 查询缓存区

如果你要对查询缓存的失效政策进行精确的控制,你必须调用 Query.setCacheRegion() 方法,为每个查询指定其命名的缓存区域。

List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
        .setEntity("blogger", blogger)
        .setMaxResults(15)
        .setCacheable(true)
        .setCacheRegion("frontpages")
        .list();

如果查询需要强行刷新其查询缓存区域,那么你应该调用org.hibernate.Query.setCacheMode(CacheMode.REFRESH)方法。 这对在其他进程中修改底层数据(例如,不通过Hibernate修改数据),或对那些需要选择性更新特定查询结果集的情况特别有用。这是对org.hibernate.SessionFactory.evictQueries() 的更为有效的替代方案,同样可以清除查询缓存区域。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值