




已阅读5页,还剩24页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Optimizing JPA Performance: An EclipseLink, Hibernate, and OpenJPA ComparisonSubmitted by Daniel Rubio on Tue, 2010/07/20 - 10:11am Tags: EclipseLink hibernate jpa OpenJPA orm Frameworks Persistence PerformanceRecommended LinksFREE eBook: JDBC Deployment Guide for WebSphere AS 6.1JDBC Connectivity Guide for JBoss ASEJB 3, JPA, and JBoss - A JDBC Connectivity Guide WebLogic 8.1 and JDBC Connectivity GuideFree Video: Why Do Type 4 JDBC Drivers Limit Modern Java Environments?Like this piece? Share it with your friends:| More This section sponsored by:Impedance mismatch. No two words encompass the troubles, headaches and quirks most developers face when attempting to link applications to relational databases (RDBMS). But lets face it, object orientated designs arent going away anytime soon from mainstream languages and neither are the relational storage systems used in most applications. One side works with objects, while the other with tables. Resolving these differences - or as its technically referred to object/relational impedance mismatch - can result in substantial overhead, which in turn can materialize into poor application performance.In Java, the Java Persistence API (JPA) is one of the most popular mechanisms used to bridge the gap between objects (i.e. the Java language) and tables (i.e. relational databases). Though there are other mechanisms that allow Java applications to interact with relational databases - such as JDBC and JDO - JPA has gained wider adoption due to its underpinnings: Object Relational Mapping (ORM). ORMs gain in popularity is due precisely to it being specifically designed to address the interaction between object and tables.In the case of JPA, there is a standard body charged with setting its course, a process which has given way to several JPA implementations, among the three most popular you will find: EclipseLink (evolved from TopLink), Hibernate and OpenJPA. But even though all three are based on the same standard, ORM being such a deep and complex topic, beyond core functionality each implementation has differences ranging from configuration to optimization techniques.What I will do next is explain a series of topics related to optimizing an applications use of the JPA, using and comparing each of the previous JPA implementations. While JPA is capable of automatically creating relational tables and can work with a series of relational database vendors, I will part from having pre-existing data deployed on a MySQL relational database, in addition to relying on the Spring framework to facilitate the use of the JPA. This will not only make it a fairer comparison, but also make the described techniques appealing to a wider audience, since performance issues become a serious concern once you have a large volume of data, in addition to MySQL and Spring being a common choice due to their community driven (i.e. open-source) roots. See the source code/application section at the end for instructions on setting up the application code discussed in the remainder of the sections.Download the Source Code associated with this article (45 MB) The basics: Metrics In order to establish JPA performance levels in an application, its vital to first obtain a series of metrics related to a JPA implementations inner workings. These include things like: What are the actual queries being performed against a RDBMS? How long does each query take? Are queries being performed constantly against the RDBMS or is a cache being used?These metrics will be critical to our performance analysis, since they will shed light on the underlying operations performed by a JPA implementation and in the process show the effectiveness or ineffectiveness of certain techniques. In this area you will find the first differences among implementations, and Im not talking about metric results, but actually how to obtain these metrics. To kick things off, I will first address the topic of logging. By default, all three JPA implementations discussed here - EclipseLink, Hibernate and OpenJPA - log the query performed against a RDBMS, which will be an advantage in determining if the queries performed by an ORM are optimal for a particular relational data model. Nevertheless, tweaking the logging level of a JPA implementation further can be helpful for one of two things: Getting even more details from the underlying operations made by a JPA - which can be turned off by default (e.g. database connection details) - or getting no logging information at all - which can benefit a production systems performance. Logging in JPA implementations is managed through one of several logging frameworks, such as Apache Commons Logging or Log4J. This requires the presence of such libraries in an application. Logging configuration of a JPA implementation is mostly done through a value in an applications persistence.xml file or in some cases, directly in a logging frameworks configuration files. The following table describes JPA logging configuration parameters: (CLICK HERE FOR LARGER IMAGE) In addition to the information obtained through logging, there is another set of JPA performance metrics which require different steps to be obtained. One of these metrics is the time it takes to perform a query. Even though some JPA implementations provide this information using certain configurations, some do not. Even so, I opted to use a separate approach and apply it to all three JPA implementations in question. After all, time metrics measured in milliseconds can be skewed in certain ways depending on start and end time criteria. So to measure query times, I will use Aspects with the aid of the Spring framework.Aspects will allow us to measure the time it takes a method containing a query to be executed, without mixing the timing logic with the actual query logic - the last feature of which is the whole purpose of using Aspects. Further discussing Aspects would go beyond the scope of performance, so next I will concentrate on the Aspect itself. I advise you to look over the accompanying source code, Aspects and Spring Aspects for more details on these topics and their configuration. The following Aspect is used for measuring execution times in query methods.view sourceprint?01.package com.webforefront.aop;02.import mons.lang.time.StopWatch;03.import mons.logging.Log;04.import mons.logging.LogFactory;05.import org.aspectj.lang.ProceedingJoinPoint;06.import org.aspectj.lang.annotation.Around;07.import org.aspectj.lang.annotation.Pointcut;08.import org.aspectj.lang.annotation.Aspect;09.10.Aspect11.public class DAOInterceptor 12.private Log log = LogFactory.getLog(DAOInterceptor.class); 13.14.Around(execution(* com.webforefront.jpa.service.*.*(.)15.public Object logQueryTimes(ProceedingJoinPoint pjp) throws Throwable 16.StopWatch stopWatch = new StopWatch();17.stopWatch.start();18.Object retVal = ceed();19.stopWatch.stop();20.String str = pjp.getTarget().toString();21.(str.substring(str.lastIndexOf(.)+1, str.lastIndexOf() + - + pjp.getSignature().getName() + : + stopWatch.getTime() + ms);22.return retVal;23.24.The main part of the Aspect is the Around annotation. The value assigned to this last annotation indicates to execute the aspect method - logQueryTimes - each time a method belonging to a class in the com.webforefront.jpa.service package is executed - this last package is where all our applications JPA query methods will reside. The logic performed by the logQueryTimes aspect method is tasked with calculating the execution time and outputting it as logging information using Apache Commons Logging.Another set of important JPA metrics is related to statistics beyond those provided by standard logging. The statistics Im referring to are things related to caches, sessions and transactions. Since the JPA standard doesnt dictate any particular approach to statistics, each JPA implementation also varies in the type and way it collects statistics. Both Hibernate and OpenJPA have their own statistics class, where as EclipseLink relies on a Profiler to gather similar metrics. Since Im already relying on Aspects, I will also use an Aspect to obtain statistics both prior and after the execution of a JPA query method. The following Aspect obtains statistics for an application relying on Hibernate.view sourceprint?01.package com.webforefront.aop;02.import org.hibernate.stat.Statistics;03.import org.hibernate.SessionFactory;04.import org.aspectj.lang.ProceedingJoinPoint;05.import org.aspectj.lang.annotation.Around;06.import org.aspectj.lang.annotation.Aspect;07.import org.springframework.beans.factory.annotation.Autowired;08.import javax.persistence.EntityManagerFactory;09.import org.hibernate.ejb.HibernateEntityManagerFactory;10.import mons.logging.Log;11.import mons.logging.LogFactory;12.13.14.Aspect15.public class CacheHibernateInterceptor 16.private Log log = LogFactory.getLog(DAOInterceptor.class);17.18.Autowired19.private EntityManagerFactory entityManagerFactory;20.21.Around(execution(* com.webforefront.jpa.service.*.*(.)22.public Object log(ProceedingJoinPoint pjp) throws Throwable 23.HibernateEntityManagerFactory hbmanagerfactory = (HibernateEntityManagerFactory) entityManagerFactory;24.SessionFactory sessionFactory = hbmanagerfactory.getSessionFactory();25.Statistics statistics = sessionFactory.getStatistics();26.String str = pjp.getTarget().toString();27.statistics.setStatisticsEnabled(true);28.(str.substring(str.lastIndexOf(.)+1, str.lastIndexOf() + - + pjp.getSignature().getName() + : (Before call) + statistics);29.30.Object result = ceed();31.(str.substring(str.lastIndexOf(.)+1, str.lastIndexOf() + - + pjp.getSignature().getName() + : (After call) + statistics);32.return result;33. 34.35.Notice the similar structure to the prior timing Aspect, except in this case the logging output contains values that belong to the Statistics Hibernate class obtained via the applications EntityManagerFactory. The next Aspect is used to obtain statistics for an application relying on OpenJPA.view sourceprint?01.package com.webforefront.aop;02.import org.apache.openjpa.datacache.CacheStatistics;03.import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;04.import org.apache.openjpa.persistence.OpenJPAPersistence;05.import org.aspectj.lang.ProceedingJoinPoint;06.import org.aspectj.lang.annotation.Around;07.import org.aspectj.lang.annotation.Aspect;08.import org.springframework.beans.factory.annotation.Autowired;09.import javax.persistence.EntityManagerFactory;10.import mons.logging.Log;11.import mons.logging.LogFactory;12.13.Aspect14.public class CacheOpenJPAInterceptor 15.private Log log = LogFactory.getLog(DAOInterceptor.class);16.17.Autowired18.private EntityManagerFactory entityManagerFactory;19.20.Around(execution(* com.webforefront.jpa.service.*.*(.)21.public Object log(ProceedingJoinPoint pjp) throws Throwable 22.OpenJPAEntityManagerFactory ojpamanagerfactory = OpenJPAPersistence.cast(entityManagerFactory);23.CacheStatistics statistics = ojpamanagerfactory.getStoreCache().getStatistics();24.String str = pjp.getTarget().toString();25.26.(str.substring(str.lastIndexOf(.)+1, str.lastIndexOf() + - + pjp.getSignature().getName() + : (Before call) Statistics start time= + statistics.start() + ,read count= + statistics.getReadCount() + ,hit count= + statistics.getHitCount() +,write count= + statistics.getWriteCount() + ,total read count= + statistics.getTotalReadCount() + ,total hit count= + statistics.getTotalHitCount() +,total write count= + statistics.getTotalWriteCount();27.28.Object result = ceed();29.30.(str.substring(str.lastIndexOf(.)+1, str.lastIndexOf() + - + pjp.getSignature().getName() + : (After call) Statistics start time= + statistics.start() + ,read count= + statistics.getReadCount() + ,hit count= + statistics.getHitCount() +,write count= + statistics.getWriteCount() + ,total read count= + statistics.getTotalReadCount() + ,total hit count= + statistics.getTotalHitCount() +,total write count= + statistics.getTotalWriteCount();31.32.return result;33. 34.Once again, notice the similar Aspect structure to the previous Aspect which relies on an applications EntityManagerFactory. In this case, the logging output contains values that belong to the CacheStatistics OpenJPA class. Since OpenJPA does not enable statistics by default, you will need to add the following two properties to an applications persistence.xml file: view sourceprint?1.2.The first property ensures statistics are gathered, while the second property is used to indicate the gathering of statistics take place on a single JVM. NOTE: The value true(EnableStatistics=true) also enables caching in addition to statistics. Since EclipseLink doesnt have any particular statistics class and relies on a Profiler to determine advanced metrics, the simplest way to obtain similar statistics to those of Hibernate and OpenJPA is through the Profiler itself. To active EclipseLinks Profiler you just need to add the following property to an applications persistence.xml file: . By doing so, the EclipseLink Profiler outputs several metrics on each JPA query method execution as logging information. Now that you know how to obtain several metrics from all three JPA implementations and understand they will be obtained as fairly as possible for all three providers, its time to put each JPA implementation to the test along with several performance techniques. JPQL queries, weaving and class transformationsLets start by making a query that retrieves data belonging to a pre-existing RDBMS table named Master. The Master table contains over 17,000 records belonging to baseball players. To simplify matters, I will create a Java class named Player and map it to the Master table in order to retrieve the records as objects. Next, relying on the Spring frameworks JpaTemplate functionality, I will setup a query to retrieve all Player objects, with the query taking the following form: view sourceprint?1.getJpaTemplate().find(select e from Player e);See the accompanying source code for more details on this last process.Next, I deploy the application using each of the three JPA implementations on Apache Tomcat, doing so separately, as well as starting and stopping the server on each deployment to ensure fair results. These are the results of doing so on a 64-bit Ubuntu-4GB RAM box, using Java 1.6: All player objects - 17,468 records Time Query Hibernate 3558 ms select player0_.lahmanID as lahmanID0_, player0_.nameFirst as nameFirst0_, player0_.nameLast as nameLast0_ from Master player0_ EclipseLink (Run-time weaver - Spring ReflectiveLoadTimeWeaver weaver ) 3215 ms SELECT lahmanID, nameLast, nameFirst FROM Master EclipseLink (Build-time weaving) 3571 ms SELECT lahmanID, nameLast, nameFirst FROM Master EclipseLink (No weaving) 3996 ms SELECT lahmanID, nameLast, nameFirst FROM Master OpenJPA (Build-time enhanced classes) 5998 ms SELECT t0.lahmanID, First, Last FROM Master t0 OpenJPA (Run-time enhanced classes- OpenJPA enhancer) 6136 ms SELECT t0.lahmanID, First, Last FROM Master t0 OpenJPA (Non enhanced classes) 7677 ms SELECT t0.lahmanID, First, Last FROM Master t0 As you can observe, the queries performed by each JPA implementation are fairly similar, with two of them using a shortcut notation (e.g. t0 and player0 for the table named Master). This syntax variation though has minimal impact on performance, since directly querying an RDBMS using any of these notation variations shows identical results. However, the query times made through several JPA implementations using distinct parameters vary considerably. One important factor leading to this time difference is due to how each implementation handles JPA entities. Lets start with the OpenJPA implementation which had the poorest times. OpenJPA can execute an enhancement process on Java entities (e.g. in this case the Player class). This enhancement process can be performed when the entities are built, at run-time or foregone altogether. As you can observe, foregoing entity enhancement altogether in OpenJPA produced the longest query times. Where as enhancing entities at either build-time or run-time produced relatively better results, with the former beating out the latter. By default, OpenJPA expects entities to be enhanced. This means you will either need to explicitly configure an application to support unenhanced classes by adding the following: view sourceprint?1.property to an applications persistence.xml file or enhance classes at build-time or at run-time relying on the OpenJPA enhancer, otherwise an application relying on OpenJPA will throw an error. Given these OpenJPA results, the remaining OpenJPA tests will be based on
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 公司环保课件培训
- 班会无神论教育
- 江苏省扬州市2024-2025学年高二下学期期末语文试题(含答案)
- 网络感知识培训
- 卤鸭餐饮培训课件下载
- 子宫内膜异位症病例讨论
- 中医内科病案分析
- 员工思想品质教育体系构建
- 自然流产病人护理常规
- 大学收心教育主题班会
- 电力建设安全工作规程完整
- 廉洁教育班会(共37张PPT)
- 通信电子线路创新训练教程部分习题答案
- 2023北京西城区初二期末(下)物理试卷及答案
- 山东省烟台招远市(五四制)2022-2023学年八年级下学期期末语文试题(解析版)
- 柳州职业技术学院辅导员考试题库
- 药学综合知识与技能
- 汽车维修服务清单
- 山东工商学院马克思主义基本原理期末复习题及参考答案
- 徐州市教师业务能力测试题库(数学)
- IMC整合营销传播培训教材课件
评论
0/150
提交评论