二级缓存 也称为进程级的缓存或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 (必须)说明了缓存的策略: 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" 的实体的属性可能无法被缓存 |
如: <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 的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。