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的英文资料整理出来的,如果有什么欠缺的地方,还请大家能指出来。我们来一起讨论讨论。共同进步吗。