`
langgufu
  • 浏览: 2310115 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hibernate实际开发中用到的东西,其缺点和优点

阅读更多
spring在管理hibernate上有独到的地方可以顺手拿来用,我也是想在能不抛弃hibernate的基础上尽可能多挖掘一下它的一些性能提升上的做法,总结大家的看法,基本得出一致结论:复杂查询依靠jdbc的sql或者hibernate提供的本地化sql封装,或者使用spring的管理,都可以提升性能和效率.我认为对于hibernate的性能优化应该是无止境的.基于大家对此的看法意见和网上的一些资料,加上自己的测试,收录如下,望大家多提宝贵意见:


在项目中使用Hibernate进行大数据量的性能测试,有一些总结,   
                1)   在处理大数据量时,会有大量的数据缓冲保存在Session的一级缓存中,这缓存大太时会严重显示性能,所以在使用Hibernate处理大数据量的,可以使用session.clear()或者session.   Evict(Object)   在处理过程中,清除全部的缓存或者清除某个对象。   
                2)   对大数据量查询时,慎用list()或者iterator()返回查询结果,   
                1.   使用List()返回结果时,Hibernate会所有查询结果初始化为持久化对象,结果集较大时,会占用很多的处理时间。   
                2.   而使用iterator()返回结果时,在每次调用iterator.next()返回对象并使用对象时,Hibernate才调用查询将对应的对象初始化,对于大数据量时,每调用一次查询都会花费较多的时间。当结果集较大,但是含有较大量相同的数据,或者结果集不是全部都会使用时,使用iterator()才有优势。   
                3.   对于大数据量,使用qry.scroll()可以得到较好的处理速度以及性能。而且直接对结果集向前向后滚动。   
                3)   对于关联操作,Hibernate虽然可以表达复杂的数据关系,但请慎用,使数据关系较为简单时会得到较好的效率,特别是较深层次的关联时,性能会很差。   
                4)   对含有关联的PO(持久化对象)时,若default-cascade= "all "或者   “save-update”,新增PO时,请注意对PO中的集合的赋值操作,因为有可能使得多执行一次update操作。   
                5)   在一对多、多对一的关系中,使用延迟加载机制,会使不少的对象在使用时方会初始化,这样可使得节省内存空间以及减少的负荷,而且若PO中的集合没有被使用时,就可减少互数据库的交互从而减少处理时间。     数据库

什么叫n+1次select查询问题?

在Session的缓存中存放的是相互关联的对象图。默认情况下,当Hibernate从数据库中加载Customer对象时,会同时加载所有关联的Order对象。以Customer和Order类为例,假定ORDERS表的CUSTOMER_ID外键允许为null,图1列出了CUSTOMERS表和ORDERS表中的记录。


以下Session的find()方法用于到数据库中检索所有的Customer对象:

List   customerLists=session.find( "from   Customer   as   c ");

运行以上find()方法时,Hibernate将先查询CUSTOMERS表中所有的记录,然后根据每条记录的ID,到ORDERS表中查询有参照关系的记录,Hibernate将依次执行以下select语句:

select   *   from   CUSTOMERS; 
select   *   from   ORDERS   where   CUSTOMER_ID=1;
select   *   from   ORDERS   where   CUSTOMER_ID=2;
select   *   from   ORDERS   where   CUSTOMER_ID=3;
select   *   from   ORDERS   where   CUSTOMER_ID=4;

通过以上5条select语句,Hibernate最后加载了4个Customer对象和5个Order对象,在内存中形成了一幅关联的对象图,参见图2。


Hibernate在检索与Customer关联的Order对象时,使用了默认的立即检索策略。这种检索策略存在两大不足:

(a)   select语句的数目太多,需要频繁的访问数据库,会影响检索性能。如果需要查询n个Customer对象,那么必须执行n+1次select查询语句。这就是经典的n+1次select查询问题。这种检索策略没有利用SQL的连接查询功能,例如以上5条select语句完全可以通过以下1条select语句来完成:

select   *   from   CUSTOMERS   left   outer   join   ORDERS 
on   CUSTOMERS.ID=ORDERS.CUSTOMER_ID 

以上select语句使用了SQL的左外连接查询功能,能够在一条select语句中查询出CUSTOMERS表的所有记录,以及匹配的ORDERS表的记录。

(b)在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象白白浪费了许多内存空间。
为了解决以上问题,Hibernate提供了其他两种检索策略:延迟检索策略和迫切左外连接检索策略。延迟检索策略能避免多余加载应用程序不需要访问的关联对象,迫切左外连接检索策略则充分利用了SQL的外连接查询功能,能够减少select语句的数目。

刚查阅了hibernate3的文档: 
查询抓取(默认的)在N+1查询的情况下是极其脆弱的,因此我们可能会要求在映射文档中定义使用连接抓取: 

<set   name= "permissions " 
                        fetch= "join "> 
        <key   column= "userId "/> 
        <one-to-many   class= "Permission "/> 
</set 
<many-to-one   name= "mother "   class= "Cat "   fetch= "join "/> 
在映射文档中定义的抓取策略将会有产生以下影响: 

通过get()或load()方法取得数据。 

只有在关联之间进行导航时,才会隐式的取得数据(延迟抓取)。 

条件查询 

在映射文档中显式的声明   连接抓取做为抓取策略并不会影响到随后的HQL查询。 

通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中,   使用HQL的左连接抓取(left   join   fetch)   对其进行重载。这将通知   Hibernate在第一次查询中使用外部关联(outer   join),直接得到其关联数据。   在条件查询   API中,应该调用   setFetchMode(FetchMode.JOIN)语句。


                6)   对于大数据量新增、修改、删除操作或者是对大数据量的查询,与数据库的交互次数是决定处理时间的最重要因素,减少交互的次数是提升效率的最好途径,所以在开发过程中,请将show_sql设置为true,深入了解Hibernate的处理过程,尝试不同的方式,可以使得效率提升。   
                7)   Hibernate是以JDBC为基础,但是Hibernate是对JDBC的优化,其中使用Hibernate的缓冲机制会使性能提升,如使用二级缓存以及查询缓存,若命中率较高明,性能会是到大幅提升。   
                  Hibernate可以通过设置hibernate.jdbc.fetch_size,hibernate.jdbc.batch_size等属性,对Hibernate进行优化。

hibernate.jdbc.fetch_size   50

hibernate.jdbc.batch_size   25

这两个选项非常非常非常重要!!!将严重影响Hibernate的CRUD性能!

C   =   create,   R   =   read,   U   =   update,   D   =   delete

Fetch   Size   是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。

例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会1次性把1万条取出来的,而只会取出Fetch   Size条数,当纪录集遍历完了这些记录以后,再去数据库取Fetch   Size条数据。

因此大大节省了无谓的内存消耗。当然Fetch   Size设的越大,读数据库的次数越少,速度越快;Fetch   Size越小,读数据库的次数越多,速度越慢。

这有点像平时我们写程序写硬盘文件一样,设立一个Buffer,每次写入Buffer,等Buffer满了以后,一次写入硬盘,道理相同。

Oracle数据库的JDBC驱动默认的Fetch   Size=10,是一个非常保守的设定,根据我的测试,当Fetch   Size=50的时候,性能会提升1倍之多,当Fetch   Size=100,性能还能继续提升20%,Fetch   Size继续增大,性能提升的就不显著了。

因此我建议使用Oracle的一定要将Fetch   Size设到50。

不过并不是所有的数据库都支持Fetch   Size特性,例如MySQL就不支持。

MySQL就像我上面说的那种最坏的情况,他总是一下就把1万条记录完全取出来,内存消耗会非常非常惊人!这个情况就没有什么好办法了  

Batch   Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。

Batch   Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。我做的一个测试结果是当Batch   Size=0的时候,使用Hibernate对Oracle数据库删除1万条记录需要25秒,Batch   Size   =   50的时候,删除仅仅需要5秒!!!

//
我们通常不会直接操作一个对象的标识符(identifier),因此标识符的setter方法应该被声明为私有的(private)。这样当一个对象被保存的时候,只有Hibernate可以为它分配标识符。你会发现Hibernate可以直接访问被声明为public,private和protected等不同级别访问控制的方法(accessor   method)和字段(field)。   所以选择哪种方式来访问属性是完全取决于你,你可以使你的选择与你的程序设计相吻合。

所有的持久类(persistent   classes)都要求有无参的构造器(no-argument   constructor);因为Hibernate必须要使用Java反射机制(Reflection)来实例化对象。构造器(constructor)的访问控制可以是私有的(private),然而当生成运行时代理(runtime   proxy)的时候将要求使用至少是package级别的访问控制,这样在没有字节码编入(bytecode   instrumentation)的情况下,从持久化类里获取数据会更有效率一些。



hibernate.max_fetch_depth   设置外连接抓取树的最大深度 
取值.   建议设置为0到3之间


就是每次你在查询时,会级联查询的深度,譬如你对关联vo设置了eager的话,如果fetch_depth值太小的话,会发多很多条sql



Hibernate的Reference之后,可以采用批量处理的方法,当插入的数据超过10000时,就flush   session并且clear。 

下面是一个测试method。

1       /**   */   /** 
2             *   测试成批插入数据的事务处理,返回是否成功 
3             *   
4             *     @param   objPO   Object 
5             *     @return   boolean 
6     */ 
7       public   boolean     insertBatch(   final     Object   objPO)       { 
8     boolean     isSuccess     =   false   ; 
9                   Transaction   transaction     =   null   ; 
10                   Session   session     =   openSession(); 
11       try     { 
12                           transaction     =   session.beginTransaction(); 
13       for     (   int     i     =   0   ;   i     <   100000   ;   i   ++   )       { 
14                                   session.save(objPO); 
15       if     (i     %   50   ==   0   )       { 
16     //     flush   a   batch   of   inserts   and   release   memory 
17                                             session.flush(); 
18                                           session.clear(); 
19                                   } 
20                           } 
21                           transaction.commit(); 
22                           logger.info(   "   transaction.wasCommitted:   " 
23     +   transaction.wasCommitted()); 
24                           isSuccess     =   true   ; 
25                     }   catch     (HibernateException   ex)       { 
26       if     (transaction     !=   null   )       { 
27       try     { 
28                                           transaction.rollback(); 
29                                           logger.error(   "   transaction.wasRolledBack:   " 
30     +   transaction.wasRolledBack()); 
31                                     }   catch     (HibernateException   ex1)       { 
32                                           logger.error(ex1.getMessage()); 
33                                           ex1.printStackTrace(); 
34                                   } 
35                           } 
36                           logger.error(   "   Insert   Batch   PO   Error:   "   +   ex.getMessage()); 
37                           ex.printStackTrace(); 
38                     }   finally     { 
39       if     (transaction     !=   null   )       { 
40                                   transaction     =   null   ; 
41                           } 
42                           session.close(); 
43                   } 
44     return   isSuccess; 
45           } 
46   

这只是简单的测试,实际项目中遇到的问题,要比这个复杂得多。 
这时候,我们可以让Spring来控制Transaction,自己来控制Hibernate的Session,随时更新数据。 
首先,利用HibernateDaoSupport类来自定义个方法打开Session;

1public   Session   openSession(){ 

3   return   getHibernateTemplate().getSessionFactory().openSession(); 

5         }

然后,用打开的Session处理你的数据;

1protected   void   doBusiness(Session   session)   { 

3   while   (true)   { 
4   //do   your   business   with   the   opening   session               
5                         someMethod(session); 
6                         session.flush(); 
7                         session.clear(); 
8                         logger.info( "good   job! ");                         
9                 } 
10}

每做一次数据操作,就更新一次Session,这样可以保证每次数据操作都成功,否则就让Spring去控制它roll   back吧。 
最后,记得关闭Session。

1     Session   session     =     openSession(); 
2   doBusiness(session); 
3   session.close();     //   关闭session
分享到:
评论

相关推荐

    ibatis 与hibernate之间的比较优点和缺点

    ### ibatis 与 hibernate 之间的比较:优点和缺点 #### 概述 在 Java 开发领域中,对象关系映射(Object Relational Mapping,简称 ORM)是一种将面向对象编程语言中的对象模型与数据库系统中的关系模型相互转换的...

    ssh框架优缺点 struts hibernate spring

    Hibernate则以其强大的ORM能力和缓存机制等优势,简化了数据库操作;而Spring框架凭借其依赖注入、面向切面编程等特性,在整个Java生态中占据了举足轻重的地位。在实际项目中,开发者需要根据具体的需求和场景,合理...

    hibernate完整开发包

    **标题与描述解析** ...综上所述,这个"hibernate完整开发包"是一个全面的资源,涵盖了从基础到高级的Hibernate使用,对于想要学习和使用Hibernate进行Java ORM开发的人员来说,是一个宝贵的工具。

    hibernate 3.1 开发包 下载

    Hibernate 3.1 开发包是Java开发人员用于对象关系映射(ORM)的一个关键工具。这个版本在ORM领域中具有重要地位,因为它为开发者提供了更...通过深入学习和实践,开发者可以充分利用其特性,提升项目的开发效率和质量。

    hibernate 开发文档发布

    《Hibernate 开发文档详解》 ...通过阅读和实践,开发者不仅可以学习到如何使用Hibernate进行数据库操作,还能了解到ORM框架的设计思想和最佳实践,从而在实际项目中更好地利用Hibernate提升开发效率和应用质量。

    hibernate开发流程 入门

    本篇将详细介绍Hibernate的开发流程,从环境搭建到实际操作,帮助初学者快速入门。 首先,我们来了解两个重要的开发工具——Database Explorer 透视图和 Hibernate 透视图。Database Explorer 透视图允许开发者在...

    Hibernate开发指南___夏昕

    这些都是在实际开发中经常遇到的技术难点,通过本书的学习,读者可以掌握解决这些问题的方法和技巧。 #### Hibernate in Spring “Hibernate in Spring”章节讨论了如何将Hibernate集成到Spring框架中,实现更高效...

    Struts,Spring,Hibernate优缺点

    Struts、Spring 和 Hibernate 是Java Web开发中三大主流的开源框架,它们各自有着独特的功能和优缺点。在构建企业级应用程序时,理解这些框架的核心特性以及它们如何相互补充至关重要。 Struts 是一个基于MVC...

    Hibernate入门到精通

    "Hibernate入门到精通" Hibernate 是一个基于Java的ORM(Object-Relational Mapping,对象关系映射)框架,它提供了一种简洁高效的方式来访问和操作关系数据库。下面是 Hibernate 的主要知识点: Hibernate 简介 ...

    JPA与Hibernate的优缺点

    Hibernate的最大优点之一是其对POJO模型的支持,这意味着开发者可以将业务对象直接映射到数据库表上,而无需进行繁琐的手动编码。Hibernate的智能缓存机制能够显著提高应用程序的性能,特别是在高并发场景下。此外,...

    Hibernate 应用开发文档+API

    首先,`Hibernate3.2 API`文档详细列出了Hibernate 3.2版本中的所有类、接口和方法,是开发过程中查询API和理解其工作原理的主要工具。通过查阅此文档,开发者可以了解如何配置SessionFactory、实体类的注解、持久化...

    spring_struts_hibernate整合开发书籍

    通过阅读这本书,读者不仅可以掌握三大框架的基本用法,还能了解到实际项目开发中的最佳实践和常见问题解决方案。 总而言之,《Spring+Struts+Hibernate整合开发》是一本面向实战的指南,它将带领读者深入了解Java ...

    hibernate开发jar包

    在实际开发中,还需要根据项目需求,确保所有必要的jar包都被包含,并正确配置Hibernate的配置文件(如hibernate.cfg.xml),以及实体类的注解或配置文件。同时,理解和熟练掌握Hibernate的API和查询语言(HQL或 ...

    Hibernate项目开发宝典源码(完整版)

    《Hibernate项目开发宝典》是一本深度探讨Java领域持久化框架Hibernate的专业书籍,它涵盖了从基础到高级的各种 Hibernate 应用场景。源码是学习和理解书中理论的最佳实践材料,而这里提供的“完整版”源码,据描述...

    hibernate开发所需包

    《Hibernate开发所需的库详解》 ...在实际开发中,还需要根据项目需求,结合具体的数据库驱动和其他相关库,才能构建出一个完整的应用系统。理解并掌握这些库的功能和使用方式,对于提升Hibernate开发效率至关重要。

    Hibernate开发指南.pdf

    本书不仅涵盖了Hibernate的基本使用方法,还包括了作者在实际项目中的经验和从Hibernate官方论坛中获得的技术洞见。 #### 二、准备工作 在开始使用Hibernate之前,有一些必要的准备工作需要完成: 1. **下载并...

    hibernate应用开发完全手册(源码)

    通过《Hibernate应用开发完全手册(源码)》中的源码分析,开发者不仅可以掌握Hibernate的基本用法,还能深入了解其内部工作机制,这对于优化代码、解决实际问题以及设计高性能的数据访问层具有重大意义。在实际项目...

    黑马程序员_hibernate框架开发2016版讲义和笔记资料_day02

    《黑马程序员_hibernate框架开发2016版讲义和笔记资料_day02》 本文将深入探讨2016年黑马程序员发布的Hibernate框架开发课程的第二天内容。Hibernate,一个强大的Java持久化框架,简化了数据库操作,为开发者提供了...

    strut spring hibernate 优缺点

    这无疑给实际开发带来了一定程度上的复杂性。 #### Spring框架 **优点:** 1. **依赖注入与面向接口编程:** Spring框架的核心功能之一是依赖注入(DI),通过这种方式可以轻松地实现对象间的解耦,使得代码更易于...

Global site tag (gtag.js) - Google Analytics