看到一篇不错的文章,于是转载过来.
几月前, 我接到一个银行的J2EE应用系统JSF+HIBERNATE+SPRING+WebService性能优化合同,静下心来几个月好好研究了一下J2EE系统的关键性能优化问题,结果非常令人吃惊,提交测试后其并发运行性能得到几倍到几十倍的提高,我想把其中的一些关键技术点总结出来,与大家共享,今天就贡献最重要的部分,HIBERNATE性能优化,以后再分别讨论JSF的分页技术,SPRING的WebServiceTemplate的应用,这些也都是IBM公司目前正在全球推广使用的最前沿的技术。
对Hibernate优化来讲,关键点包括the second-level cache 如ehcache(OScache,JBosscache), 数据fetch策略以避免太密集的数据库query accesses 和增进并发性.
开发环境是:IBM Websphere 6.1server/RAD7/IBM DB2 9/Spring 2.5/Hibernate 3.0/JSF.
1.首先建立ehcache, 我做了一下几件事:
a)在ApplicationContext.xml文件中增加一些配置:
...
<bean id="hibernateSessionID" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> …… <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_second_level_cache">True</prop> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> </bean> <bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="/WEB-INF/ehcache.xml"/> </bean> <!-- A facade to the Ehcache cache class --> <bean id="cacheProviderFacade"
class="org.springmodules.cache.provider.ehcache.EhCacheFacade"> <property name="cacheManager" ref="cacheManager" /> </bean>
...
|
b) 在ORM映射文件中增加属性:
<cache usage = "read-write"/>
|
CustomerOrder.hbm.xml;
CustomerOffer.hbm.xml;
Customer.hbm.xml
CustomerAccount.hbm.xml
........
c) 在Web Application Library 目录增加一些类库:
Spring-modules-cache.jar ; ehcache.jar
d) 把文件 ehcache.xml 放在 WEB-INF\ehcache.xml
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <cache name="com.???.???.domain.CustomerOrder" maxElementsInMemory="50" eternal="false" timeToIdleSeconds="100" timeToLiveSeconds="100" overflowToDisk="false" /> </ehcache>
|
e) 对查询结果 QueryResult cache, 如下修改源码:
CustomerDAO.java:
........
queryObject.setCacheable(true);
return queryObject.list();
.........
2. 如何得到 eh-cache 统计命中率:
a) 在 ApplicationContext.xml增加配置:
<bean id="hibernateSessionID" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> …… <prop key="hibernate.generate_statistics">true</prop> </props> </property> </bean>
|
b) 修改package com.xxx.yyy.dao.impl中类CustmerOrderExtDAO.java的方法queryWithPaging:
private List queryWithPaging(final String queryStr,
final String[] paramNames,
final Object[] values,
final int pageNum,
final int maxRowsPerPage){
……
Statistics stats =getHibernateTemplate().getSessionFactory().getStatistics();
long l2HitCount = stats.getSecondLevelCacheHitCount();
long l2MissCount = stats.getSecondLevelCacheMissCount();
long queryHitCount = stats.getQueryCacheHitCount();
long queryMissCount = stats.getQueryCacheMissCount();
System.out.println("L2_Cache_Hit :"+l2HitCount);
System.out.println("L2_Cache_Miss :"+l2MissCount);
double l2CacheHitRatio = l2HitCount / (l2HitCount + l2MissCount + 0.000001);
System.out.println("L2_Cache_Hit_Ratio :"+l2CacheHitRatio);
System.out.println("");
System.out.println("Query_Cache_Hit :"+queryHitCount);
System.out.println("Query_Cache_Miss :"+queryMissCount);
……
Return result
}
c)模拟多个客户并发访问类似的数据,我们得到很好的结果:
EH cache 命中率逐渐收敛到接近75%左右。
3. Hibernate fetch strategy(solve N+1 select problem):
a) 在文件 ApplicationContext.xml中增加配置:
...... <bean id="hibernateSessionID" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="hibernateProperties"> <props> …… <prop key="hibernate.cache.use_minimal_puts">true</prop> <prop key="hibernate.use_outer_join">true</prop> <prop key="hibernate.max_fetch_depth">3</prop> </props> </property> </bean> ......
|
b) 在Hibernate 映射文件中配置属性 fetch = “join”:
CustomerOrder.hbm.xml;
CustomerOffer.hbm.xml;
Customer.hbm.xml
CustomerAccount.hbm.xml
........
........
c)看结果,当我们通过以下配置打开数据库SQL query时:
true
我们能够看到hibernate比以前只需要更少的数据库访问次数,因为它能够在二级EHcache中找到大部分的数据。
阅读(2596) | 评论(0) | 转发(0) |