Hibernate缓存配置/批量处理

  Hibernate除了自动对Session级别的事务进行一级缓存外,二级缓存都需要实现org.hibernate.cache.CacheProvider接口,Hibernate已经实现了一些缓存,开发人员可以直接配置使用,同时要启用二级缓存,配置hibernate.cache.use_second_level_cache为true。

可选值:

  1. org.hibernate.cache.HashtableCacheProvide
  2. org.hibernate.cache.EhCacheProvider
  3. org.hibernate.cache.OSCacheProvider
  4. org.hibernate.cache.SwarmCacheProvider
  5. org.hibernate.cache.TreeCacheProvider...


例如:
(1).hibernate.cfg.xml

Xml代码 复制代码
  1. <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>  
  2. <property name="hibernate.cache.use_second_level_cache">true</property>   
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property> 


(2)spring

Xml代码 复制代码
  1. <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>  
  2. <prop key="hibernate.cache.use_second_level_cache">true</prop>   
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop> 



   Hibernate在默认情况下并不会对所有实体对象进行缓存,所以,我们需要指定缓存哪些对象,在实体对象的映射文件中(相应的<class>标签内部),添加如下配置:
<cache usage="read-only"/> 或者在hibernate.cfg.xml中添加如下配置:
<class-cache class="com.xxx.hibernate.XXClass" usage="read-only"/>

usage="read-only"是“只读”缓存策略。

注意,这个<cache>标签只能放在<class>标签的内部,而且必须处在<id>标签的前面。

    Hibernate二级缓存是SessionFactory级的缓存,它允许多个Session间共享,使用时需要使用第三方的缓存组件,新版Hibernate将EHcache作为默认的二级缓存实现.

    缓存同步策略:缓存同步策略决定了数据对象在缓存中的存取规则,我们必须为每个实体类指定相应的缓存同步策略.Hibernate中提供了4种不同的缓存同步策略:
    1.read-only:只读.对于不会发生改变的数据可使用.
    2.nonstrict-read-write:如果程序对并发访问下的数据同步要求不严格,且数据更新频率较低,采用本缓存同步策略可获得较好性能.
    3.read-write:严格的读写缓存.基于时间戳判定机制,实现了"read committed"事务隔离等级.用于对数据同步要求的情况,但不支持分布式缓存,实际应用中使用最多的缓存同步策略.
    4.transactional: 事务型缓存,必须运行在JTA事务环境中.此缓存中,缓存的相关操作被添加到事务中(此缓存类似于一个内存数据库),如事务失败,则缓冲池的数据会一同回 滚到事务的开始之前的状态.事务型缓存实现了"Repeatable read"事务隔离等级,有效保证了数据的合法性,适应于对关键数据的缓存,Hibernate内置缓存中,只有JBossCache支持事务型缓存.

各种缓存实现

  1. hibernate.cache.use_minimal_puts:是否优化二级缓存来最小化读写操作,集群时的缓存优化。可选值:true(默认):启用最小化读写操作。false:禁用最小化读写操作。
  2. hibernate.cache.use_query_cache:是否缓存查询结果(条件查询时用)。可选值:true:缓存查询结果。false:不缓存查询结果
  3. hibernate.cache.use_second_level_cache:否启用二级缓存。可选值:true:启用二级缓存。false:不使用二级缓存。
  4. hibernate.cache.query_cache_factory:设置自定义的查询缓存类全名,缓存类必须实现org.hibernate.cache.QueryCache接口。可选值:(1)org.hibernate.cache.StandardQueryCache(默认)。(2)自定义缓存实现类。
  5. hibernate.cache.region_prefix:二级缓存的前缀名称。
  6. hibernate.cache.use_structured_entries:是否使用结构化的方式缓存对象。可选值:true:结构化方式缓存对象。false:不使用结构化的方式缓存对象。


附:echcache.xml

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>      
  2. <ehcache>  
  3.     <diskStore path="java.io.tmpdir"/>  
  4.     <defaultCache  
  5.         maxElementsInMemory="10000"  
  6.         eternal="false"  
  7.         timeToIdleSeconds="120"  
  8.         timeToLiveSeconds="120"  
  9.         overflowToDisk="true"/>  
  10.            
  11.      <cache  name="org.hibernate.cache.StandardQueryCache"          
  12.           maxElementsInMemory="10000"          
  13.           eternal="false"          
  14.           timeToIdleSeconds="200"          
  15.           timeToLiveSeconds="500"          
  16.           overflowToDisk="true"/>  
  17.                 
  18.      <cache name ="org.hibernate.cache.UpdateTimestampsCache"    
  19.          maxElementsInMemory ="5000"  
  20.          eternal ="true"    
  21.          overflowToDisk ="true"/>    
  22.         
  23. </ehcache>  
<?xml version="1.0" encoding="UTF-8"?>   
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"/>
        
     <cache  name="org.hibernate.cache.StandardQueryCache"       
		  maxElementsInMemory="10000"       
		  eternal="false"       
		  timeToIdleSeconds="200"       
		  timeToLiveSeconds="500"       
		  overflowToDisk="true"/>
		     
     <cache name ="org.hibernate.cache.UpdateTimestampsCache" 
		 maxElementsInMemory ="5000"
		 eternal ="true" 
		 overflowToDisk ="true"/> 
     
</ehcache>

 

  • maxElementsInMemory属性用于指定缓存中最多可放多少个对象。
  • eternal属性指定缓存是否永久有效。
  • timeToIdleSeconds属性指定缓存闲置多久未被使用便清理掉。
  • timeToLiveSeconds属性指定缓存的生命长度。
  • diskPersistent属性指定缓存是否被持久化到硬盘中,保存路径由<diskStore>标签指定。


测试时,log4j.properties

Java代码 复制代码
  1. log4j.logger.org.hibernate=warn      
  2. log4j.logger.org.hibernate.cache=debug  
log4j.logger.org.hibernate=warn   
log4j.logger.org.hibernate.cache=debug



批量处理:
由于Hibernate对这两种缓存有着不同的管理机制,对于二级缓存,我们可以对它的大小进行相关配置,而对于内部缓存,Hibernate就采取了“放任自流”的态度了,对它的容量并没有限制。现在症结找到了,我们做海量数据插入的时候,生成这么多的对象就会被纳入内部缓存(内部缓存是在内存中做缓存的),这样你的系统内存就会一点一点的被蚕食,如果最后系统被挤“炸”了,也就在情理之中了。

    我们想想如何较好的处理这个问题呢?有的开发条件又必须使用Hibernate来处理,当然有的项目比较灵活,可以去寻求其他的方法。

   这里推荐两种方法:
   (1):优化Hibernate,程序上采用分段插入及时清除缓存的方法。
   (2):绕过Hibernate API ,直接通过 JDBC API 来做批量插入,这个方法性能上是最 好的,也是最快的。
    对于上述中的方法1,其基本是思路为:优化Hibernate,在配置文件中设置hibernate.jdbc.batch_size参数,来指定每次提交SQL的数量;程序上采用分段插入及时清除缓存的方法(Session实现了异步write-behind,它允许Hibernate显式地写操作的批处理),也就是每插入一定量的数据后及时的把它们从内部缓存中清除掉,释放占用的内存。
     设置hibernate.jdbc.batch_size参数,可参考如下配置。

Xml代码 复制代码
  1. <hibernate-configuration>  
  2. <session-factory>  
  3. .........   
  4. <property name=” hibernate.jdbc.batch_size”>50</property>  
  5. .........   
  6. <session-factory>  
  7. <hibernate-configuration>  
<hibernate-configuration>
<session-factory>
.........
<property name=” hibernate.jdbc.batch_size”>50</property>
.........
<session-factory>
<hibernate-configuration>



配置hibernate.jdbc.batch_size参数的原因就是尽量少读数据库,hibernate.jdbc.batch_size参数值越大,读数据库的次数越少,速度越快。从上面的配置可以看出,Hibernate是等到程序积累到了50个SQL之后再批量提交。

    hibernate.jdbc.batch_size参数值也可能不是设置得越大越好,从性能角度上讲还有待商榷。这要考虑实际情况,酌情设置,一般情形设置30、50就可以满足需求了。

Java代码 复制代码
  1. Session session=HibernateUtil.currentSession();   
  2. Transatcion tx=session.beginTransaction();   
  3. for(int i=0;i<10000;i++)   
  4. ...{   
  5. Student st=new Student();   
  6. st.setName(“feifei”);   
  7. session.save(st);   
  8. if(i%50==0//以每50个数据作为一个处理单元    
  9. ...{   
  10. session.flush(); //保持与数据库数据的同步    
  11. session.clear(); //清除内部缓存的全部数据,及时释放出占用的内存    
  12. }   
  13. }   
  14. tx.commit();   
  15. .........  
Session session=HibernateUtil.currentSession();
Transatcion tx=session.beginTransaction();
for(int i=0;i<10000;i++)
...{
Student st=new Student();
st.setName(“feifei”);
session.save(st);
if(i%50==0) //以每50个数据作为一个处理单元 
...{
session.flush(); //保持与数据库数据的同步 
session.clear(); //清除内部缓存的全部数据,及时释放出占用的内存 
}
}
tx.commit();
.........



在一定的数据规模下,这种做法可以把系统内存资源维持在一个相对稳定的范围。

    注意:前面提到二级缓存,在这里有必要再提一下。如果启用了二级缓存,从机制上讲Hibernate为了维护二级缓存,我们在做插入、更新、删除操作时,Hibernate都会往二级缓存充入相应的数据。性能上就会有很大损失,所以建议在批处理情况下禁用二级缓存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值