一:hibernate一级缓存
一级缓存很短和session的生命周期一致,一级缓存也叫session级的缓存或事务级缓存
一级缓存是缓存实体对象的,不会缓存普通属性
那些方法支持一级缓存:
* get()
* load()
* iterate(查询实体对象)
如何管理一级缓存:
* session.clear(),session.evict()
如何避免一次性大量的实体数据入库导致内存溢出
* 先flush,再clear
向数据库中批量加入1000条数据
for (int i=0; i<1000; i++) {
Student student = new Student();
student.setName("s_" + i);
session.save(student);
//每20条数据就强制session将数据持久化
//同时清除缓存,避免大量数据造成内存溢出
if ( i % 20 == 0) {
session.flush();
session.clear();
}
}
如果数据量特别大,考虑采用jdbc实现,如果jdbc也不能满足要求可以考虑采用数据本身的特定导入工具
二:hibernate二级缓存
二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是 hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider如果使用查询缓存,加上hibernate.cache.use_query_cache=true
缓存可以简单的看成一个Map,通过key在缓存里面找value。
二级缓存也称进程级的缓存或SessionFactory级的缓存,二级缓存可以被所有的session共享,二级缓存的生命周期和SessionFactory的生命周期一致。hibernate为实现二级缓存,只提供二级缓存的接口供第三方来实现(具体可以查看http://www.redsaga.com/hibernateref/3.2/html/performance.html#performance-cache)。二级缓存也是缓存实体对象 ,其实现原理与一级缓存的差不多吧,其方法与一级的相同,只是缓存的生命周期不一样而已:
* get()
* load()
* iterate(查询实体对象)
其中 Query 和Criteria的list() 只会缓存,但不会使用缓存(除非结合查询缓存)。
二级缓存的配置和使用:
* 将echcache.xml文件拷贝到src下
* 开启二级缓存,修改hibernate.cfg.xml文件
<property name="hibernate.cache.use_second_level_cache">true</property>
* 指定缓存产品提供商,修改hibernate.cfg.xml文件
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
* 指定那些实体类使用二级缓存(两种方法)
* 在映射文件中采用<cache>标签
* 在hibernate.cfg.xml文件中,采用<class-cache>标签其缓存策略有read-only,read-write,nonstrict-read-write,transactional,(详细查看http://www.redsaga.com/hibernateref/3.2/html/performance.html#performance-cache 这里有详细介绍;)这里的缓存策略是针对你缓存里面的对象而言的,就比如read-only,它是限制缓存中的对象不能被修改的。
三、查询缓存
查询缓存是针对普通属性结果集的缓存,对实体对象的结果集只缓存id(其ID不是对象的真正ID,它与查询的条件相关即where后的条件相关,不同的查询条件,其缓存的id也不一样) ,查询缓存的生命周期,当前关联的表发生修改或是查询条件改变时,那么查询缓存生命周期结束,它不受一级缓存 和二级缓存 的生命周期的影响,要想使用查询缓存需要手动配置如下:
* 在hibernate.cfg.xml文件中启用查询缓存,如:
<property name="hibernate.cache.use_query_cache">true</property>
* 在程序中必须手动启用查询缓存,如:
query.setCacheable(true);
其中 Query 和Criteria的list() 就可利用到查询缓存了。
管理Hibernate的缓存
Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。
SessionFactory有一个内置缓存和一个外置缓存,其中外置缓存是可插拨的缓存插件,也被称为Hibernte的第二级缓存。
缓存的实现不仅需要作为物理介质的硬件,同时还需要用于管理缓存的并发访问和过期等策略的软件。因此,缓存是通过软件和硬件同时实现的。
1. Hibernate的Session的缓存中存发的数据是数据库中数据的拷贝。在数据库数据表现为关系数据形式,而在Session的缓存中数据表现为相互关联的对象。在读写数据库时,Session会负责这两种形式的数据的映射。Session在某些时间点会按照缓存中的数据来同步更新数据库,这一过程称为清理缓存。
2.SessionFactory的缓存可分为两类:内置缓存和外置缓存。SessionFactory的内置还促和Session的缓存在实现方式上比较相似,前者时指SessionFactory对象的一些集合属性宝航的数据,后者是指Session的一些集合属性。SessionFactory的内置缓存中村发了映射员数据和预定义SQL语句,映射员数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据到出来的。SessionFactory的内置缓存是制度缓存,应用不能修改缓存中映射元数据和预定义的SQL语句,SessionFactory无需进行内置缓存与映射文件的同步。
3.SessionFactory的外置缓存和Session
比较Hibernate的第一级缓存和第二级缓存的区别
| 区别之处 | 第一级缓存 | 第二级缓存 |
| 存放数据的形式 | 相互关联的持久化对象 | 对象的散装数据 |
| 缓存范围 | 事务范围,每个事务拥有单独的第一级缓存 | 进程或群级范围,缓存被同一个进程或群级范围内的所有事务共享 |
| 并发访问策略 | 由于每个事务都拥有单独的第一级缓存,不会出现并发问题,因此无需提供并发访问策略 | 由于多个事务会同时访问第二级缓存中相同数据,因此必须提供适当的并发访问策略,来保证特定的事务隔离级别 |
| 数据过期策略 | 没有提供过期策略处于第一级缓存中的对象永远不会过期,除非应用程序显示清空缓存或者清除特定的对象。 | 必须提供数据过期策略,如基于内存的缓存中的对象最大数目,允许对象处于缓存中的最长时间,以及允许对象处于缓存中的最大空闲时间。通过maxElementsInMemory等 进行设置。 |
| 物理介质 | 内存 | 内存和硬盘 |
| 缓存的软件实现 | Session的实现中包含了缓存的实现 | 由第三方提供,Hibernate仅提供一些缓存适配器。 |
| 启用缓存的方式 | 通过Session接口执行保存、更新等操作,Hibernate就会启用第一级缓存,把数据库中的数据以对象的形式拷贝到缓存中。 | 可通过单个集合的粒度上配置第二级缓存。如果类的实例被经常读但很少修改,就可以考虑第二级缓存。只要为某个类或集合配置了第二级缓存,Hibernate在运行时才会把它的实例加入第二级缓存 |
| 用户管理缓存的方式 | 由于内存的容量有限,必须通过恰当的检索策略和检索方式来限制加载对象的数目。Session的evit()可以显示清空缓存中特定对象,但不推荐这种方法 | 可以存放大量的数据,数据过期策略的maxElementsInMemory属性值可以控制内存中的对象数目。管理:选择需要使用第二级缓存的持久化类,设置合适的并发访问策略;选择合适的缓存适配器,设置合适的过期策略。SessionFactory的evit()也可以显示清空缓存中特定对象,但不推荐这种方法。 |
只有符合下面条件的数据才适合与存放到第二级缓存中
Session为应用程序提供了两个管理缓存的方法:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。 如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。
本文深入探讨Hibernate的一级和二级缓存机制,包括缓存的管理、配置及使用方法,并对比了不同缓存的区别。
1689

被折叠的 条评论
为什么被折叠?



