首页 > 代码库 > hibernate之性能优化

hibernate之性能优化

        hibernate是建立在JDBC基础上的框架,但他有很多JDBC所无法比拟的性能优化技术。下面介绍几种优化策略。

1.使用dynamic-insert与dynamic-update

        在class标签中使用该属性,可以设置hibernate动态的生成SQL语句,而不是在hibernate启动时就生成预设的SQL语句。

        当其设置为true时,hibernate会根据实际需求设置新增或更新的字段,而不是所有的字段。

<class name="com.hibernate.book" table="BOOK" dynamic-insert="true" dynamic-update="true">

2.延迟加载

        为了避免在关联查询中带来无谓的开销而使用,即尽在需要读取数据库时才查询数据库。session的load()方法采用了,get()则没有。

(1)持久化对象的延迟加载

        配置:

                  <class name="com.hibernate.Category" table="CATEGORY" lazy="true"> 

        下述操作不会输出任何sql语句:

        Category category= (Category) session.load(Category.class, new Integer(1));

        tx.commit();

注:

load()方法获取的不是真正的持久化对象,而是一个代理对象(包含目标对象的属性和方法)。

代理对象仅需要得到持久化类对象的引用,不需要获取所有属性值。

为顺利生成代理对象,hibernate的持久化类必须有公开的构造方法,不能声明为final。

(2)集合对象的延迟加载

        地位:是延迟加载最重要的部分可以大幅度提高性能。

        配置:

                   <class name="com.hibernate.Category" table="CATEGORY" lazy="true">  

                    <set name="products" cascade="save-update" inverse="true" lazy="false">

        .....
  </set>
 </class>

        下面操作不会查询product表的值:

                     Category category= (Category) session.load(Category.class, new Integer(1));

  System.out.println(category.getName());
  tx.commit();
注:
        product集合设置lazy=‘extra‘后,调用product的size(), contains(), 和isEmpty()方法不会引发不必要的查询。

(3)属性的延迟加载

        一些数据库表有大数据字段类型(blob,clob),但其使用麻烦,且大多数情况下对提高性能有限。

(4)延迟加载出现的违例问题

    使用hibernate.initialize():在session关闭之前强制加载被关联的对象。

    使用open session in view设计模式。

3. 集合对象的抓取策略

概念:指hibernate在读取关联对象时所采取的策略。

(1)查询抓取(select fetching):先通过一个sql语句查询持久化对象,再通过另一个查询语句查询关联的对象。设置该策略后仍可使用HQL或者Criteria对象重载抓取策略。

(2)子查询抓取(Subselect fetching):先通过一个sql语句查询持久化对象,再通过另一个子查询语句查询关联的对象。

(3)链接抓取(join fetching):使用外连接语句获取当前对象或者相关的对象。不会对使用HQL语句的查询生效,只对其他查询方式如:session.get(),criteria.list()有效。

(4)批量查询(Batch fetching):先通过查询获取一个主键或外键列表,再使用单条语句获取对象。hibernate在查询时会按照设置的数值分批查询数据。

4. hibernate的“1+N”问题

场景1:

          Query对象的iterate()方法获取查询数据。当代码第一次使用iterate()方法时,hibernate会先获取id列表值,再通过N条语句获取数据并添加到缓存中。

        若Query对象的iterate()方法总不能很好地命中缓存数据时,将大大影响其性能,此时可以采用list()方法;反之,若可以很好地命中缓存,则可很好地提高性能。

场景2:

        一对多,在一方查找得到了n个对象, 那么又需要将n个对象关联的集合取出,于是本来的一条sql查询变成了n+1条 。

        多对一,在多方查询得到了m个对象,那么也会将m个对象对应的1方的对象取出, 也变成了m+1。  
解决: 
(1)使用延迟加载,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。
(2)采用二级缓存, 即使第一次查询很慢,之后命中缓存也是很快的。


注:本文参考《Hibernate开发与实战》 刘伟 张利国 电子工业出版社 一书

本文出自 “java我的最爱” 博客,请务必保留此出处http://lindianli.blog.51cto.com/7129432/1433817