Hibernate性能优化1( 转)


有不少人认为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> 该设置对性能的提高比较有限
相关文章
相关标签/搜索