HibernateSession是事务级别的持久化数据缓存。再为每个类或者每个集合配置一个集群或者JVM级别(SessionFactory级别)的缓存也是有可能的。你甚至可以插入一个集群的缓存。要小心,缓存永远不会知道其他进程可能对持久化仓库(数据库)进行的修改(即使他们可能设定为经常对缓存的数据进行失效)。
默认情况下,Hibernate使用EHCache进行JVM级别的缓存。但是,对JCS的支持现在已经被废弃了,未来版本的Hibernate将会去掉它。通过hibernate.cache.provider_class属性,你也可以指定其他缓存,只要其实现了net.sf.hibernate.cache.CacheProvider接口。
Table 12.1. Cache Providers
Cache | Provider class | Type | Cluster Safe | Query Cache Supported |
---|---|---|---|---|
Hashtable (not intended for production use) | net.sf.hibernate.cache.HashtableCacheProvider | memory | yes | |
EHCache | net.sf.ehcache.hibernate.Provider | memory, disk | yes | |
OSCache | net.sf.hibernate.cache.OSCacheProvider | memory, disk | yes | |
SwarmCache | net.sf.hibernate.cache.SwarmCacheProvider | clustered (ip multicast) | yes (clustered invalidation) | |
JBoss TreeCache | net.sf.hibernate.cache.TreeCacheProvider | clustered (ip multicast), transactional | yes (replication) |
类或者集合映射的<cache>元素可能有下列形式:
<cache
usage="transactional|read-write|nonstrict-read-write|read-only" />
![]() |
usage 指定了缓存策略: transactional, read-write, nonstrict-read-write 或者 read-only |
另外 (推荐首选?), 你可以在hibernate.cfg.xml中指定<class-cache> 和 <collection-cache> 元素。
usage属性指明了缓存并发策略(cache concurrency strategy)。
如果你的应用程序需要读取一个持久化类的实例,但是并不打算修改它们,可以使用read-only 缓存。这是最简单,也是实用性最好的策略。甚至在集群中,它也能完美地运作。
<class name="eg.Immutable" mutable="false"> .... <jcs-cache usage="read-only"/> </class>
如果应用程序需要更新数据,可能read-write缓存比较合适。如果需要可序列化事务隔离级别(serializable transaction isolation level),这种缓存决不能使用。如果在JTA环境中使用这种缓存,你必须指定hibernate.transaction.manager_lookup_class属性的值,给出得到JTA TransactionManager的策略。在其它环境中,你必须确保在Session.close()或者Session.disconnect()调用前,事务已经结束了。 如果你要在集群环境下使用这一策略,你必须确保底层的缓存实现支持锁定(locking)。内置的缓存提供器并不支持。
<class name="eg.Cat" .... > <jcs-cache usage="read-write"/> .... <set name="kittens" ... > <jcs-cache usage="read-write"/> .... </set> </class>
如果程序偶尔需要更新数据(也就是说,出现两个事务同时更新同一个条目的现象很不常见),也不需要十分严格的事务隔离,可能适用nonstrict-read-write缓存。如果在JTA环境中使用这种缓存,你必须指定hibernate.transaction.manager_lookup_class属性的值,给出得到JTA TransactionManager的策略。在其它环境中,你必须确保在Session.close()或者Session.disconnect()调用前,事务已经结束了。
transactional缓存策略提供了对全事务缓存提供,比如JBoss TreeCache的支持。这样的缓存只能用于JTA环境,你必须指定hibernate.transaction.manager_lookup_class。
没有一种缓存提供器能够支持所有的缓存并发策略。下面的表列出每种提供器与各种并发策略的兼容性。
Table 12.2. 缓存并发策略支持(Cache Concurrency Strategy Support)
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 |
不管何时你传递一个对象给save(), update()或者 saveOrUpdate() ,或者不管何时你使用load(), find(), iterate()或者filter()取得一个对象的时候,该对象被加入到Session的内部缓存中。当后继的flush()被调用时,对象的状态会和数据库进行同步。如果你在处理大量对象并且需要有效的管理内存的时候,你可能不希望发生这种同步,evict()方法可以从缓存中去掉对象和它的集合。
Iterator cats = sess.iterate("from eg.Cat as cat"); //a huge result set while ( cats.hasNext() ) { Cat cat = (Cat) iter.next(); doSomethingWithACat(cat); sess.evict(cat); }
Session也提供了一个contains()方法来判断是否一个实例处于这个session的缓存中。
要把所有的对象从session缓存中完全清除,请调用Session.clear()。
For the JVM-level JCS cache, there are methods defined on SessionFactory for evicting the cached state of an instance, entire class, collection instance or entire collection role.
对于第二层缓存来说,在SessionFactory中定义了一些方法来从缓存中清除一个实例、整个类、集合实例或者整个集合。
查询结果集也可以被缓存。只有当经常使用同样的参数进行查询时,这才会有些用处。要使用查询缓存,首先你要打开它,设置hibernate.cache.use_query_cache=true这个属性。这样会创建两个缓存区域——一个保存查询结果集(net.sf.hibernate.cache.QueryCache),另一个保存最近查询的表的时间戳(net.sf.hibernate.cache.UpdateTimestampsCache)。请注意查询缓存并不缓存结果集中包含实体的状态;它只缓存标识符属性的值和值类型的结果。所以查询缓存通常会和第二层缓存一起使用。
大多数查询并不会从缓存中获得什么好处,所以默认查询是不进行缓存的。要进行缓存,调用 Query.setCacheable(true)。这个调用会让查询在执行时去从缓存中查找结果,或者把结果集放到缓存去。
如果你要对查询缓存的失效政策进行精确的控制,你必须调用Query.setCacheRegion()来为每个查询指定一个命名的缓存区域。
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger order by blog.datetime desc") .setEntity("blogger", blogger) .setMaxResults(15) .setCacheable(true) .setCacheRegion("frontpages") .list();