Hibernate性能优化(一)

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行非常轻量级的封装,使得JAVA

程序员可以随心所欲地使用对象编程思维来操作数据库。
Hibernate性能优化
第一,尽量降低访问数据库的次数
    Cache:hibernate中有两次缓存,一级位于Session部分是必需的,第二级位于

SessionFactory的外置缓存(SessionFactory缓存分两类,内置缓存和外置缓存,其中内置缓存

存放映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在

hibernate初始化阶段根据映射元数据推导出来的),二级缓存不是必需的,由开发人员自行指定

,二级缓存能明显提高系统性能,但同时也会消耗内存,可通过配置文件来指定内存中能够加载

的最多元素,有利于避免消耗过多内存。
    在批量更新和批量删除时,通过绕过hibernate API,直接通过JDBC API来执行SQL语句,可

以提高效率。
    比如更新一万条记录
    tx = session.beginTransaction();
    Connection con = session.connection();
    PreparedStatement stmt = con.prepareStatement("update Customer set age=age+1

where age>0");
    tx.commit();
当然,使用存储过程效果更佳
    create or replace procedure batchUpdateCustomer(p_age in number) as
    begin
      update customer set age=age+1 where age>p_age;
    end;
    tx = session.beginTransaction();
    Connection con = session.connection();
    String procedure = "{call batchUpdateCustomer(?)}";
    CallableStatement cstmt = con.prepareCall(procedure);
    cstmt.setInt(1,0);
    cstmt.executeUpdate();
    tx.commit();

    二级缓存的设置,第一种直接在hbm.xml中增加Cache元素,指明使用策略,如read-

only,read-write等。
    <class name="" table="">
      <cache usage="read-write"/>
        ...........
    配置echcache.xml
<ehcache>
<diskStore path="c:\\temp"/>
<defaultCache
     maxElementsInMemory="10000"
     eternal="false"
     timeToIdleSeconds="120"
     timeToLiveSeconds="120"
     overflowToDisk="true"
/>
<cache name="mypack.class"
     maxElementsInMemory="10000"
     eternal="false"
     timeToIdleSeconds="120"
     timeToLiveSeconds="120"
     overflowToDisk="true"
/>
</ehcache>

第二适当的检索方式
    延迟检索:对一些基本属性字段将其lazy设置为false,而对于一些可能需要消耗内存的字段

,如clob,将其lazy设置为true,对于集合全部设为true。(class和set中有些属性)  
    不管是延迟检索还是立即检索都可以通过batch-size设置批量检索的数量。合理取值在3-10

间(class和set元素中有些属性)。

第三避免无用的查询
    使用投影查询,只查出实例的一部分字段
    使用iterate()方法,在有些情况下轻微提高查询性能。因为iterate()首先检索ID字段,然

后根据ID字段到hibernate的第一级缓存及二级缓存中查找匹配的对象,若存在,直接加入到检

索结果集中,否则执行额外的select语句,根据ID字段到数据库中检索对象。
    使用查询缓存,这样第一次执行查询语句时,会把查询结果放在第二级缓存中,注意二级缓

存中存放的只是实体的OID,对投影查询,会存放所有的数据值。
    启用查询缓存步骤:
    1.配置二级缓存
    2.在hibernate的hibernate.properties配置文件中设置查询缓存属性;
      hibernate.cache.use_query_cache=true
    3.Query query = session.createQuery("from customer c where c.age>:age");
      query.setInteger("age",age);
      query.setCacheable(true);


有很多人认为Hibernate天生效率比较低,确实,在普遍情况下,需要将执行转换为SQL语句的Hibernate的效率低于直接JDBC存取,然而,在经过比较好的性能优化之后,Hibernate的性能还是让人相当满意的,特别是应用二级缓存之后,甚至可以获得比较不使用缓存的JDBC更好的性能,下面介绍一些通常的Hibernate的优化策略:
     1.抓取优化
     抓取是指Hibernate如何在关联关系之间进行导航的时候,Hibernate如何获取关联对象的策略,其主要定义了两个方面:如何抓取和何时抓取
     1)如何抓取。
     Hibernate3主要有两种种抓取方式,分别应用于对象关联实例(many-to-one、one-to-one)和对象关联集合(set、map等),总共是四种变种
     JOIN抓取: 通过在SELECT语句中使用OUTER JOIN来获得对象的关联实例或者关联集合)
     SELECT抓取: 另外发送一条SELECT语句来抓取当前对象的关联实体和集合
     在我的开发经历中,此处对性能的优化是比较有限的,并不值得过多关注
     例:
     A.应用于对象关联实例(默认是false)
     <many-to-one name=".." outer-join="true/false/auto"   .../>
     B.应用于对象关联集合(默认是auto)
     <set name=".." fetch="join/select" ... >
        ....
     </set>
     2)何时抓取
     主要分为延迟加载和立即抓取,默认的情况下Hibernate3对对象关联实采用延迟加载,普通属性采用立即抓取,通过延迟加载和采用适当的抓取粒度,与不采用优化相比往往可以将性能提升数倍
     立即抓取:当抓取宿主对象时,同时抓取其关联对象和关联集以及属性
     延迟加载:当抓取宿主对象时,并不抓取其关联对象,而是当对其对象进行调用时才加载
     例:
     A.应用于对象关联实例(默认是延迟加载)
     <many-to-one name=".."   lazy="true/false" .../>
     B.应用于对象关联集合(默认是延迟加载)
     <set name=".." lazy="true/false" ... >
        ....
     </set>
     对于延迟加载,需要注意的时,对延迟对象的使用必须在Session关闭之前进行,Hibernate的LazyInitalizationException往往就是由于在Session的生命期外使用了延迟加载的对象。当我们进行Web开发时,可以使用OpenSessionInView模式,当请求开始时打开session,当请求响应结束时才关闭session,不过,在使用OpenSessionInView模式时,需要注意如果响应时间比较长(业务比较复杂或者客户端是低速网络),将Session资源(也就是数据库的连接)占用太久的话可以会导致资源耗尽
     3)抓取粒度
     抓取粒度指的是对象在关联关系之间被导航时一次预先加载的数量,Hibernate程序的性能比较差往往就在于没有对抓取粒度仔细考虑,当加载一个列表并在列表中的每个对象中对其关联进行导航时,往往导致N+1条SQL语句查询。
     例:
     A.应用于对象关联实例(默认为1),注意,对对象关联实例的设置是在被关联的对象之上的,譬如
     class User
     {
         Group g;
     }
     那么抓取粒度应该在Group的配置文件之上,见下
     <class name="Group" table="group" batch-size="..">
         ...
     </class>
     对该值并没有一个约定俗成的值,根据情况而定,如果被关联表数据比较少,则可以设置地小一些,3-20,如果比较大则可以设到30-50,注意的时候,并不是越多越好,当其值超过50之后,对性能并没有多大改善但却无谓地消耗内存
     假设有如下例子:
        List<User> users = query.list();
     如果有20个User,并对这20个User及其Group进行遍历,如果不设置batch-size(即batch-size="1"),则在最糟糕的情况
     下,需要1 + 20条SQL语句,如果设置batch-size="10",则最好的情况下只需要1 + 2条SQL语句
     B.应用于对象关联集合(默认为1)
     <set name=".." batch-size="" ... >
        ....
     </set>
     2.二级缓存
     Hibernate对数据的缓存包括两个级:一级缓存,在Session的级别上进行,主要是对象缓存,以其id为键保存对象,在Session的生命期间存在;二级缓存,在SessionFactory的级别上进行,有对象缓存和查询缓存,查询缓存以查询条件为键保存查询结果,在SessionFactory的生命期间存在。默认地,Hibernate只启用一级缓存,通过正确地使用二级缓存,往往可以获得意想不到的性能。
     1)对象缓存:
     当抓取一个对象之后,Hiberate将其以id为键缓存起来,当下次碰到抓取id相同的对象时,可以使用如下配置
     方法1:在缓存对象上配置
     <class ...>
        <cache useage="read-only/write/...." regions="group" />
     </class>
     useage表示使用什么类型的缓存,譬如只读缓存、读写缓存等等(具体参见Hibernate参考指南),值得注意的时,有部分缓存在Hibernate的实现中不支持读写缓存,譬如JBossCache在Hibernate的实现中只是一种只读缓存,具体缓存实现对缓存类型的支持情况,可以参见org.hibernate.cache包
     regions表示缓存分块,大部分的缓存实现往往对缓存进行分块,该部分是可选的,详细参见各缓存实现
     方法2:在hibernate.cfg.xml中配置
     <cache class=".." useage=".." regions=".."/>
     我认为第二种更好,可以统一管理
     2)查询缓存
     查询时候将查询结果以查询条件为键保存起来,需要配置如下
     A.在hibernate.cfg.xml中配置(启用查询缓存)
     <property name="hibernate.cache.use_query_cache">true</property>   (前面的属性名可参见常量
org.hibernate.cfg.Enviroment.USE_QUERY_CACHE)
     B.程序
     query.setCacheable(true);
     query.setCacheRegions(...);
     需要注意的是,查询缓存与对象缓存要结合更有效,因为查询缓存仅缓存查询结果列表的主键数据
     一般情况下在开发中,对一些比较稳定而又被频繁引用的数据,譬如数据字典之类的,将其进行二级缓存,对一些查询条件和查询数据变化不频繁而又常常被使用的查询,将其进行二级缓存。由于二级缓存是放在内存中,而且Hibernate的缓存不是弱引用缓存(WeekReference),所以注意不要将大块的数据放入其中,否则可能会被内存造成比较大的压力。
     3.批量数据操作
     当进行大批量数据操作(几万甚至几十几百万)时,需要注意两点,一,批量提交,二,及时清除不需要的一级缓存数据
     1)所谓的批量提交,就是不要频繁使用session的flush,每一次进行flush,Hibernate将PO数据于数据库进行同步,对于海量级数据操作来说是性能灾难(同时提交几千条数据和提交一条数据flush一次性能差别可能会是几十倍的差异)。一般将数据操作放在事务中,当事务提交时Hibernate自动帮你进行flush操作。
     2)及时清除不需要的一级缓存数据:由于Hibernate默认采用一级缓存,而在session的生命期间,所有数据抓取之后会放入一级缓存中,而当数据规模比较庞大时,抓取到内存中的数据会让内存压力非常大,一般分批操作数据,被一次操作之后将一级缓存清除,譬如
     session.clear(User.class)
     4.杂项
     dynamic-insert,dynamic-update,动态插入和动态更新,指的是让Hibernate插入数据时仅插入非空数据,当修改数据时只修改变化的数据,譬如对于
     class User
     {
        id
        username
        password
     }
     如果u.id=1, u.username="ayufox",u.password=null,那么如果不设置动态插入,则其sql语句是insert into users(id, username, password) values (1, 'ayufox', '),如果设置则其sql语句是insert into users(username) valeus('ayufox')
     在如上的情况下,如果修改u.password='11',那么如果不设置动态更新,则sql语句为update users set username='ayufox', password='11' where id = 1,如果设置则为update user set password='11' where d = 1
     设置是在class的映射文件中,如下
     <class name="User" table="users" dynamic=insert="true/false" dynamic-update="true/false" ...>
     </class>
  该设置对性能的提升比较有限

http://hi.baidu.com/jellywgd/blog/item/4b8cc380e6d4e7d19023d982.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值