Hibernate二级缓存的使用


无锡达内----周谦 Email:somken@163.com 0 / 9 Hibernate 的缓存机制 基本信息 缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时, 也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并 发访问和缓存数据的生命周期。 Hibernate 的 缓 存 包 括 Session 的 缓 存 和 SessionFactory 的 缓 存 , 其 中 SessionFactory 的缓存又可以分为两类:内置缓存和外置缓存。Session 的缓存是内置的, 不能被卸载,也被称为 Hibernate 的第一级缓存。SessionFactory 的内置缓存和 Session 的缓存在实现方式上比较相似,前者是 SessionFactory 对象的一些集合属性包含的数据, 后者是指 Session 的一些集合属性包含的数据。SessionFactory 的内置缓存中存放了映射 元数据和预定义 SQL 语句,映射元数据是映射文件中数据的拷贝,而预定义 SQL 语句是在 Hibernate 初始化阶段根据映射元数据推导出来,SessionFactory 的内置缓存是只读的,应 用程序不能修改缓存中的映射元数据和预定义 SQL 语句,因此 SessionFactory 不需要进行 内置缓存与映射文件的同步。SessionFactory 的外置缓存是一个可配置的插件。在默认情 况下,SessionFactory 不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓 存的介质可以是内存或者硬盘。SessionFactory 的外置缓存也被称为 Hibernate 的第二级缓 存。 Hibernate 的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝,那么它们 之间的区别是什么呢?为了理解二者的区别,需要深入理解持久化层的缓存的两个特性:缓 存的范围和缓存的并发访问策略。 设置 hibernate 缓存的属性是 lazy=true 就是设置缓存的 上一句是错的 lazy=true 是 设置延迟加载的. 持久化层的缓存的范围 缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。 1 事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当 无锡达内----周谦 Email:somken@163.com 1 事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库 事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形 式。 2 进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此 必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时, 缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是 内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松 散的对象数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化 的算法要求更快。 3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数 据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致 性,缓存中的数据通常采用对象的松散数据形式。 对大多数应用来说,应该慎重地考虑是否需要使用集群范围的缓存,因为访问的速度 不一定会比直接访问数据库数据的速度快多少。 持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据, 还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。 事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是 持久化层的第二级缓存,通常是可选的。 持久化层的缓存的并发访问策略 当多个并发的事务同时访问持久化层的缓存的相同数据时,会引起并发问题,必须采 用必要的事务隔离措施。 在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下 四种类型的并发访问策略,每一种策略对应一种事务隔离级别。 事务型:仅仅在托管环境中适用。它提供了 Repeatable Read 事务隔离级别。对于 经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这 类的并发问题。 读写型:提供了 Read Committed 事务隔离级别。仅仅在非集群的环境中适用。对于 无锡达内----周谦 Email:somken@163.com 2 经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。 非严格读写型:不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓 存中相同数据的可能,必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对 于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。 只读型:对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。 事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越 高,并发性能就越低。 什么样的数据适合存放到第二级缓存中? 1 很少被修改的数据 2 不是很重要的数据,允许出现偶尔并发的数据 3 不会被并发访问的数据 4 参考数据 不适合存放到第二级缓存的数据? 1 经常被修改的数据 2 财务数据,绝对不允许出现并发 3 与其他应用共享的数据。 Hibernate 的二级缓存 如前所述,Hibernate 提供了两级缓存,第一级是 Session 的缓存。由于 Session 对 象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓 存。第一级缓存是必需的,不允许而且事实上也无法卸除。在第一级缓存中,持久化类的每 个实例都具有唯一的 OID。 无锡达内----周谦 Email:somken@163.com 3 第二级缓存是一个可插拔的的缓存插件,它是由 SessionFactory 负责管理。由于 SessionFactory 对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围 或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题, 因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配 器用于把具体的缓存实现软件与 Hibernate 集成。第二级缓存是可选的,可以在每个类或每 个集合的粒度上配置第二级缓存。 Hibernate 的二级缓存策略的一般过程如下: 1) 条件查询的时候,总是发出一条 select * from table_name where „. (选择所有 字段)这样的 SQL 语句查询数据库,一次获得所有的数据对象。 2) 把获得的所有数据对象根据 ID 放入到第二级缓存中。 3) 当 Hibernate 根据 ID 访问数据对象的时候,首先从 Session 一级缓存中查;查不 到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照 ID 放入到缓存。 4) 删除、更新、增加数据的时候,同时更新缓存。 Hibernate 的二级缓存策略,是针对于 ID 查询的缓存策略,对于条件查询则毫无作用。 为此,Hibernate 提供了针对条件查询的 Query 缓存。 Hibernate 的 Query 缓存策略的过程如下: 1) Hibernate 首先根据这些信息组成一个 Query Key,Query Key 包括条件查询的请 求一般信息:SQL, SQL 需要的参数,记录范围(起始位置 rowStart,最大记录个数 maxRows),等。 2) Hibernate 根据这个 Query Key 到 Query 缓存中查找对应的结果列表。如果存在, 无锡达内----周谦 Email:somken@163.com 4 那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据 Query Key 放入到 Query 缓存中。 3) Query Key 中的 SQL 涉及到一些表名,如果这些表的任何数据发生修改、删除、 增加等操作,这些相关的 Query Key 都要从缓存中清空。 1.1 1 启用 Hibernate 二级缓存 Hibernate 二级缓存分为两部分,class 缓存和查询缓存,其获取对象的方式有所不同,但两 者也有联系,查询缓存必须以 class 缓存为基础才能起作用,否则只会使效率更低。 我们这里使用的二级缓存是通过 ehcache 第三方插件实现的。 1.1.1 1.1 配置 Hibernate.cfg.xml 启用 class 缓存: org.hibernate.cache.EhCacheProvider 启用查询缓存: true 1.1.2 1.2 配置 Spring 框架中的 hibernate 启用 class 缓存: org.hibernate.cache.EhCacheProvider 启用查询缓存: true 1.1.3 1.3 配置 ehcache Ehcache 配置文件为 ehcache.xml,默认配置为: 无锡达内----周谦 Email:somken@163.com 5 其中各项内容的含义为: 1 diskStore:代表当二级缓存对象数据在内存中溢出,如果需要写入文件 系统时的文件目录。 2 defaultCache:默认的 calss 缓存配置,如果某个对象没有其专有的配置 时,ehcache 一律启用默认配置。 3 maxElementInMemory:对象在内存中可存放的最大数量。 4 eternal:表示对象永不过期,如果选 true 则 5,6 两项无效。 5 timeToIdleSeconds:对象的空闲状态过期时间,单位为秒,0 为可以无 限制空闲。 6 timeToLiveSeconds:对象存在的最长时间,单位为秒(注意,如果该项 比 5 项要小,则第 5 项无意义),0 为永不过期。 7 overflowToDisk:当对象在内存中的数量超过 maxElementInMemory 值 时,如果该项为 true,则 ehcahe 会把对象数据写入 diskStore 项指定的目录。 如果需要对某个具体对象进行单独配置时,可以加上一组 cache 配置,例如: 另外还有两个特殊的 cache 配置: 这两个 cache 配置对应查询缓存,具体作用如下(摘用别人的描述): 无锡达内----周谦 Email:somken@163.com 6 “当 hibernate 更新数据库的时候,它怎么知道更新哪些查询缓存呢? hibernate 在一个 地方维护每个表的最后更新时间,其实也就是放在上面 UpdateTimestampsCache 所指定的缓 存配置里面。 当通过 hibernate 更新的时候,hibernate 会知道这次更新影响了哪些表。然后它更新这 些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当 hibernate 查 询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查 询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么 这个缓存是无效的。 可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查 询缓存的命中率可能会比较低。” 当然,如果没有这两个配置,则 ehcache 将为查询缓存启用默认配置。 1.2 2 如何使用 class 缓存 1.2.1 2.1 对象缓存 Class 缓存的作用主要是在内存中保存某个具体对象,当用户第一次通过 get、iterator 方式取 出对象时,系统会先从 class 缓存中去找,如果没有再通过 sql 语句去数据库中查找相关记录, 并将查询到的对象放入内存中。 实例:对某个对象使用二级缓存,只需要在该对象的 hbm 文件中配置即可 我们注意到其中 usage 这个选项,它有多个选择,对应不同的含义,经常有这两种种: 1 read-only:只对缓存中的对象进行读操作。 2 read-write:当对象被 update 时,缓存中和数据库中一同被修改(缓存 不支持事务回滚)。 1.2.2 2.2 关联缓存 目前我们仅仅实现了对一个对象的缓存,那如何对该对象的关联对象集合进行缓存 呢? 实例:对某个对象的关联对象集合的二级缓存,需要在该对象的 hbm 文件中 set 配置进 行修改 注意: 1 只对 one-to-many 有效,而且仅仅缓存的是关联对象的 id 集合,如果需 要实现完全缓存,则需要对关联的对象也配置成使用二级缓存。 无锡达内----周谦 Email:somken@163.com 7 2 集合缓存是独立的,不受关联对象添加、删除的影响,如果要修改集合 内容,必须对这个集合本身进行修改,例如:codelist.getChildren().add()。 1.3 3 如何使用查询缓存 查询缓存,目的是为了将通过 list()方法的查询结果存入缓存中,并实现对语句的缓存,如 果下次用户在使用这条语句进行查询时,将直接从缓存中获取对象数据。 这里要注意的是,查询缓存必须配合 class 缓存使用,如果只启用查询缓存,不对查询对象 启用二级缓存,则会大大降低查询效率。 因为,当第一次通过启用查询缓存的 session 进行语句查询时,系统只执行一次数据库查询 将所有的记录取出,并将对象存入 class 缓存,语句及 id 集合存入查询缓存;而当用户第二次查 询该语句时,系统将先执行去查询缓存中查找,取出所有符合条件的 id 集合,如果这时候该对 象的 class 缓存没启用或在 class 缓存中已过期,系统将根据 id,一个个去数据库 load,实际上是 进行了 1+N 次查询。 实际上,在我们系统中,并不是对所有对象都要进行二级缓存,而 spring 框架中提供的 hibernate 方法,虽然有 getHibernateTemplate().setCacheQueries(),但该方法影响的是全局的配置, 一旦启用,将会对不需要缓存的查询造成不良影响。 于是,我自己在 hibernateService()中添加了一个方法: public List findByCachedQuery(final String hql) { return (List) getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Query queryObject = session.createQuery(hql); queryObject.setCacheable(true); if (getHibernateTemplate().getQueryCacheRegion() != null) { queryObject.setCacheRegion(getHibernateTemplate().getQueryCacheRegion()); } return queryObject.list(); } }, true); } 这样,将只在 session 范围内启用查询缓存,一旦该 session 结束了,那么查询缓存也将回复 默认配置。 注意:使用时只支持 hql。 1.4 4 注意事项 在使用二级缓存时,注意,所有对数据库的修改都必须走 hibernate,如果从其他系统来或使 用 sql 语句来修改数据库相关记录,那么将对二级缓存的数据不会造成影响,换句话说,缓存中 的对象数据将和数据库中的不一致 无锡达内----周谦 Email:somken@163.com 8
还剩8页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

herpin

贡献于2012-06-11

下载需要 5 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf