与Session相对的是,SessionFactory也提供了相应的缓存机制。SessionFactory缓存可以依据功能和目的的不同而划分为内置缓存和外置缓存。 SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的副本,而预定义SQL语句是在 hibernate初始化阶段根据映射元数据推导出来的。SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义 SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。
SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据 的副本,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的二级缓存。
Hibernate的二级缓存的实现原理与一级缓存是一样的,也是通过以ID为key的Map来实现对对象的缓存。
由于Hibernate的二级缓存是作用在SessionFactory范围内的,因而它比一级缓存的范围更广,可以被所有的Session对象所共享。
14.2.3.1 二级缓存的工作内容 Hibernate的二级缓存同一级缓存一样,也是针对对象ID来进行缓存。所以说,二级缓存的作用范围是针对根据ID获得对象的查询。
二级缓存的工作可以概括为以下几个部分:
● 在执行各种条件查询时,如果所获得的结果集为实体对象的集合,那么就会把所有的数据对象根据ID放入到二级缓存中。 ● 当Hibernate根据ID访问数据对象的时候,首先会从Session一级缓存中查找,如果查不到并且配置了二级缓存,那么会从二级缓存中查找,如果还查不到,就会查询数据库,把结果按照ID放入到缓存中。 ● 删除、更新、增加数据的时候,同时更新缓存。 14.2.3.2 二级缓存的适用范围 Hibernate的二级缓存作为一个可插入的组件在使用的时候也是可以进行配置的,但并不是所有的对象都适合放在二级缓存中。
在通常情况下会将具有以下特征的数据放入到二级缓存中:
● 很少被修改的数据。 ● 不是很重要的数据,允许出现偶尔并发的数据。 ● 不会被并发访问的数据。 ● 参考数据。 而对于具有以下特征的数据则不适合放在二级缓存中:
● 经常被修改的数据。 ● 财务数据,绝对不允许出现并发。 ● 与其他应用共享的数据。 在这里特别要注意的是对放入缓存中的数据不能有第三方的应用对数据进行更改(其中也包括在自己程序中使用其他方式进行数据的修改,例如,JDBC),因为那样Hibernate将不会知道数据已经被修改,也就无法保证缓存中的数据与数据库中数据的一致性。
14.2.3.3 二级缓存组件 在默认情况下,Hibernate会使用EHCache作为二级缓存组件。但是,可以通过设置 hibernate.cache.provider_class属性,指定其他的缓存策略,该缓存策略必须实现 org.hibernate.cache.CacheProvider接口。
通过实现org.hibernate.cache.CacheProvider接口可以提供对不同二级缓存组件的支持。
Hibernate内置支持的二级缓存组件如表14.1所示。
表14.1 Hibernate所支持的二级缓存组件 组件
| Provider类
| 类型
| 集群
| 查询缓存
| Hashtable
| org.hibernate.cache.HashtableCacheProvider
| 内存
| 不支持
| 支持
| EHCache
| org.hibernate.cache.EhCacheProvider
| 内存,硬盘
| 最新支持
| 支持
| OSCache
| org.hibernate.cache.OSCacheProvider
| 内存,硬盘
| 不支持
| 支持
| SwarmCache
| org.hibernate.cache.SwarmCacheProvider
| 集群
| 支持
| 不支持
| JBoss TreeCache
| org.hibernate.cache.TreeCacheProvider
| 集群
| 支持
| 支持
| Hibernate已经不再提供对JCS(java Caching System)组件的支持了。
14.2.3.4 二级缓存的配置 在使用Hibernate的二级缓存时,对于每个需要使用二级缓存的对象都需要进行相应的配置工作。也就是说,只有配置了使用二级缓存的对象才会被放置在二级缓存中。二级缓存是通过<cache>元素来进行配置的。<cache>元素的属性定义说明如下所示:
- <cache
- usage="transactional|read-write|nonstrict-read-write|read-only"
- region="RegionName"
- include="all|non-lazy"
- />
复制代码
表14.2 <cache>元素的属性说明 序号
| 属性
| 含义和作用
| 必须
| 默认值
| (1)
| usage
| 指定缓存策略,可选的策略包括:transactional,read-write,nonstrict-read-write或read-only
| Y
| (2)
| region
| 指定二级缓存区域名
| N
| (3)
| include
| 指定是否缓存延迟加载的对象。all,表示缓存所有对象;non-lazy,表示不缓存延迟加载的对象
| N
| all
| 14.2.3.5 二级缓存的策略 当多个并发的事务同时访问持久化层的缓存中的相同数据时,会引起并发问题,必须采用必要的事务隔离措施。
在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下4种类型的并发访问策略,每一种策略对应一种事务隔离级别。
● 只读缓存(read-only) 如果应用程序需要读取一个持久化类的实例,但是并不打算修改它们,可以使用read-only缓存。这是最简单,也是实用性最好的策略。
对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。
● 读/写缓存(read-write) 如果应用程序需要更新数据,可能read-write缓存比较合适。如果需要序列化事务隔离级别,那么就不能使用这种缓存策略。
对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。
● 不严格的读/写缓存(nonstrict-read-write) 如果程序偶尔需要更新数据(也就是说,出现两个事务同时更新同一个条目的现象很不常见),也不需要十分严格的事务隔离,可能适用nonstrict-read-write缓存。
对于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。
● 事务缓存(transactional) transactional缓存策略提供了对全事务的缓存,仅仅在受管理环境中使用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。
在上面所介绍的隔离级别中,事务型并发访问策略的隔离级别最高,然后依次是读/写型和不严格读写型,只读型的隔离级别最低。事务的隔离级别越高,并发性能就越低。
14.2.3.6 在开发中使用二级缓存 在这一部分中,将细致地介绍如何在Hibernate中使用二级缓存。在这里所使用的二级缓存组件为EHCache。
关于EHCache的详细信息请参考http://ehcache.sourceforge.net上的内容。
在Hibernate中使用二级缓存需要经历以下步骤:
● 在Hibernate配置文件(通常为hibernate.cfg.xml)中,设置二级缓存的提供者类。 ● 配置EHCache的基本参数。 ● 在需要进行缓存的实体对象的映射文件中配置缓存的策略。 下面就来逐步演示一下如何在开发中使用Hibernate的二级缓存。
修改Hibernate的配置文件
在使用Hibernate的二级缓存时,需要在Hibernate的配置文件中指定缓存提供者对象,以便于Hibernate可以通过其实现对数据的缓存处理。
在这里需要设置的参数是hibernate.cache.provider_class,在使用EHCache时,需要将其值设置为org.hibernate.cache.EhCacheProvider。具体要增加的配置如下所示:
- <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider</property>
复制代码
Hibernate配置文件的详细内容请参考配套光盘中的hibernate"src"cn"hxex" hibernate"cache"hibernate.cfg.xml文件。
增加EHCache配置参数
在默认情况下,EHCache会到classpath所指定的路径中寻找ehcache.xml文件来作为EHCache的配置文件。
在配置文件中,包含了EHCache进行缓存管理时的一些基本的参数。具体的配置方法如清单14.9所示。
清单14.9 EHCache的配置
- <?xml version="1.0" encoding="UTF-8"?>
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="ehcache.xsd">
- <diskStore path="java.io.tmpdir" />
- <defaultCache
- maxElementsInMemory="10000"
- eternal="false"
- timeToIdleSeconds="120"
- timeToLiveSeconds="120"
- overflowToDisk="true"
- diskPersistent="false"
- diskExpiryThreadIntervalSeconds="120"
- memoryStoreEvictionPolicy="LRU" />
- </ehcache>
复制代码- 在这里只是使用EHCache所提供的默认配置文件进行了EHCache的基本配置,对于这些参数的详细含义请参考其官方网站(http: //ehcache.sourceforge.net/)中的资料。在实际的开发中,应该依据自己的具体情况来设置这些参数的值。
- 开发实体对象
- 这里所使用的是一个非常简单的User对象,它只包含了ID,name和age三个属性,具体的实现方法请参见配套光盘中的hibernate"src"cn"hxex"cache"User.java文件。
- 配置映射文件
- 映射文件的配置与不使用二级缓存的Java对象的区别就在于需要增加前面所介绍的<cache>元素来配置此对象的缓存策略。在这里所使用的缓存策略为“read-write”。所以,应该在映射文件中增加如下的配置:
- <cache usage="read-write"/>
复制代码
|