Hibernate缓存详解

为了提高系统性能,hibernate也使用了缓存机制。在hibernate框架中,主要包含两个方面的缓存,一级缓存和二级缓存。hibernate缓存的作用主要表现在以下两个方面: 1) 通过主键(ID)加载数据的时候 .2) 延迟加载中。

一级缓存:
hibernate的一级缓存是由session提供的,因此它只存在session的生命周期中。也就是说session关闭的时候该session所管理的一级缓存也随之被清除。一个线程对应一个session,一个线程可以看成一个用户。也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了。hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存。如果tb事务提交或回滚了,我们称session就关闭了,生命周期结束了。hibernate的一级缓存是session所内置的,默认开启,不能被卸载,也不能进行任何配置。在缓存中的对象,具有持久性,session对象负责管理.一级缓存的优点是使用同一个session对象多次查询同一个数据对象,仅对数据库查询一次。一级缓存采用的是Key-Value的MAP方式来实现的。在缓存实体对象时,对象的主关键字ID是MAP的Key,实体对象就是对象的值。所以说一级缓存是以实体对象为单位进行存储的。访问的时候使用的是主键关键字ID。一级缓存使用的是自动维护的功能。但可以通过session提供的手动方法对一级缓存的管理进行手动干预。evict()方法用于将某个对象从session的一级缓存中清除。clear()方法用于将session缓存中的方法全部清除。

注意:清理缓存前,要手动调用flush方法同步到数据库,否则save的对象就没有保存到数据库里。
注意:大批量数据的添加还是不要使用hibernate,这是hibernate弱项。可以使用jdbc(速度也不会太快,只是比hibernate好一点),或者使用工具产品来实现,比如oracle的Oracle SQL Loader,导入数据特别快。 

缓存和连接池的区别:缓存和池都是放在内存里,实现是一样的,都是为了提高性能的。但有细微的差别,池是重量级的,里面的数据是一样的,比如一个池里放100个Connection连接对象,这个100个都是一样的。缓存里的数据,每个都不一样。比如读取100条数据库记录放到缓存里,这100条记录都不一样。


二级缓存:
二级缓存的实现原理与一级缓存是一样的。也是通过Key-Value的Map来实现对对象的缓存。二级缓存是作用在SessionFactory范围内的。因此它它可被所有的Session对象所共享。需要注意的是放入缓存中的数据不能有第三方的应用对数据进行修改。


二级缓存默认关闭,需要程序员手动开启。首先导入ehcache.jar二级缓存包。然后,在src下添加ehcache.xml配置,同时,在hibernate.cfg.xml中启用二级缓存。


//默认配置,所有的类都遵循这个配置
<defaultCache
        //缓存里可以放10000个对象
        maxElementsInMemory="10000"
        //过不过期,如果是true就是永远不过期
        eternal="false"
        //一个对象被访问后多长时间还没有访问就失效(120秒还没有再次访问就失效)
        timeToIdleSeconds="120"
        //对象存活时间(120秒),如果设置永不过期,这个就没有必要设了
        timeToLiveSeconds="120"
        //溢出的问题,如果设成true,缓存里超过10000个对象就保存到磁盘里
        overflowToDisk="true"
        />


我们也可以对某个对象单独配置:
<cache name="com.bjpowernode.hibernate.Student"
        maxElementsInMemory="100"
        eternal="false"
        timeToIdleSeconds="10000"
        timeToLiveSeconds="10000"
        overflowToDisk="true"
        />


还需要在hibernate.cfg.xml配置文件配置缓存,让hibernate知道我们使用的是那个二级缓存。
<!-- 配置缓存提供商 -->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider</property>
<!-- 启用二级缓存,这也是它的默认配置 -->
<property name="hibernate.cache.use_second_level_cache">true</property>

启用二级缓存的配置可以不写的,因为默认就是true开启二级缓存。
必须还手动指定那些实体类的对象放到缓存里在hibernate.cfg.xml里:

//在<sessionfactory>标签里,在<mapping>标签后配置
<class-cache class="com.bjpowernode.hibernate.Student" usage="read-only"/>

或者在实体类映射文件里:

//在<class>标签里,<id>标签前配置
<cache usage="read-only"/>

usage属性表示使用缓存的策略,一般优先使用read-only,表示如果这个数据放到缓存里了,则不允许修改,如果修改就会报错。这就要注意我们放入缓存的数据不允许修改。因为放缓存里的数据经常修改,也就没有必要放到缓存里。


使用read-only策略效率好,因为不能改缓存。但是可能会出现脏数据的问题,这个问题解决方法只能依赖缓存的超时,比如上面我们设置了超时为120秒,120后就可以对缓存里对象进行修改,而在120秒之内访问这个对象可能会查询脏数据的问题,因为我们修改对象后数据库里改变了,而缓存却不能改变,这样造成数据不同步,也就是脏数据的问题。


第二种缓存策略read-write,当持久对象发生变化,缓存里就会跟着变化,数据库中也改变了。这种方式需要加解锁,效率要比第一种慢。还有两种策略,请看hibernate文档,最常用还是第一二种策略。


注意:大批量的数据添加时可能会出现溢出,解决办法是每当天就20个对象后就清理一次一级缓存。如果我们使用了二级缓存,光清理一级缓存是不够的,还要禁止一二级缓存交互,在save方法前调用session.setCacheMode(CacheMode.IGNORE)。
if (i % 20 == 0) {
session.flush();//清理缓存前,要手动调用flush方法同步到数据库,否则save的对象就没有保存到数据库里。
//清除缓存的内容
session.clear();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值