Hibernate缓存

 

缓存的作用主要用来提高性能,可以简单的理解成一个Map;使用缓存涉及到三个操作:把数据放入缓存、从缓存中获取数据、删除缓存中的无效数据。

一级缓存,Session级共享。

save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都会将对象放在一级缓存中,一级缓存不能控制缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;可以用evict,clear方法清除缓存中的内容。

随着sesssion的关闭session缓存就关闭了

看到hqlsql语句就不能从一级缓存中取,例如Query

-------------------------------------------------------------------------------------------------------

二级缓存,SessionFactory级共享。

·实现为可插拔,通过修改cache.provider_class参数来改变;

hibernate内置了对EhCache,OSCache,TreeCache,SwarmCache的支持可以通过实现CacheProviderCache接口来加入Hibernate不支持的缓存实现。

·hibernate.cfg.xml中加入:

<class-cache class="className" usage="read-only"/>

或在映射文件的class元素加入子元素:

<cache usage="read-write"/>

其中usage:

read-only只读 

read-write严格读写,多线程时会做同步 

nonstrict-read-write不严格的读写 

Transactional事务性缓存 

·Session的save(这个方法不适合native生成方式的主键),

update,saveOrUpdate,list,iterator,get,load,以及Query,Criteria都会填充二级缓存,但只有(没打开查询缓存时)Sessioniterator,get,load会从二级缓存中取数据(iterator可能存在N+1次查询)

·Query,Criteria(查询缓存)由于命中率较低,所以hibernate默认是关闭;修改cache.use_query_cachetrue打开对查询的缓存,并且调用query.setCacheable(true)criteria.setCacheable(true)

·SessionFactory中提供了evictXXX()方法用来清除缓存中的内容。例:HibernateUtil.getSessionFactory().evict(User.class);

·统计信息打开generate_statistics,用sessionFactory.getSatistics()获取统计信息。

 

例子:

Hibernate采用第三方缓存控制,我们使用oscache来演示首先需要加入oscache2.1.jar这个库文件,在Hibernate3.3.2lib文件夹下的optional文件夹内。

另外需要加入oscache的配置文件,在Hibernate3.3.2/porject/etc下找到oscache.proprities文件,黏贴到工程src目录下即可

我用的是Hibernate3.3.2,还需要加载common-logging-1.1.jar这个库,因为oscache使用的日志框架是common-logging

添加完以后我们修改hibernate.cfg.xml配置文件:加入

<!-- 二级缓存 -->  
<property name="cache_user_second_level_cache">true</property>  <!-- 使用二级缓存 -->  
<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property> <!--使用oscache-->

另外我们还需要指定哪些类需要采用缓存机制,以Users为例

修改Users.hbm.xml配置(还可以在hibernate.cfg.xml配置:<class-cache class="domain.Users(全类名)" usage="read-only"/>

 

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE hibernate-mapping PUBLIC  
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
<hibernate-mapping package="domain">  
    <class name="Users">  
        <cache usage="read-write"/>  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"></property>  
        <property name="birthday"></property>         
    </class>  
</hibernate-mapping>  

 

下面输出一下oscache的统计信息看看,即cache的命中率,当然打开统计信息消耗不少的资源(开发测试时可能要看)

hibernate.cfg.xml中加入

<!-- 打开二级缓存统计信息 -->
<property name="generate_statistics">true</property>  

 

程序代码中:

 Statistics st = HibernateUtil.getSessionFactory().getStatistics();
 System.out.println(st);
System.out.println("put:" + st.getSecondLevelCachePutCount());//加入二级缓存次数
System.out.println("hit:" + st.getSecondLevelCacheHitCount());//命中次数
System.out.println("miss:" + st.getSecondLevelCacheMissCount());//没有命中次数
 

 

 

-------------------------------------------------------------------------------------------------------------

·分布式缓存和中央缓存。

大型的系统往往是一台数据库,多台web服务器,那么如何协调好多台web服务器上的缓存同步就会存在很大的问题。

比如u1 u2 两个用户分别访问w1 w2 两台服务器,同时读取了user对象信息,那么两台服务器上的数据就会分别保存在w1 w2的缓存上,如果u1更新了user的信息,那么w2的缓存依然还是没更新前的数据,u2读到的数据不是正确的数据。

这种分布式缓存对更新的成本比较高

另外是把缓存独立出来,w1 w2共用一台缓存服务器(中央缓存),那么更新方面的问题是解决了,但是读取数据的开销也大了,不再是本地缓存读取,需要连接缓存服务器读取了。

·使用缓存的条件

1.读取大于修改。

2.数据量不能超过内存容量。

3.对数据要有独享的控制。

4.可以容忍出现无效数据。

你可能感兴趣的:(多线程,Hibernate,xml,Web,cache)