3.1 延迟加载

1、  <class lazy=”false”>

  配置如下

1     tx = session.beginTransaction();

2 Person p=(Person) session.load(Person.class, "001");//(1)

3     System.out.println("");//(2)

4     System.out.println("0: "+p.getPersonId());//(3)

5     System.out.println("0: "+p.getName());//(4)

6     System.out.println("0: "+p.getSchool());//(5)

7     tx.commit();

1<property name="name" type="java.lang.String">

2<column name="NAME"/>

3</property>

4<property name="school" type="java.lang.String" lazy="true">

5<column name="SCHOOL"></column>

6</property>

      当运行到p的时候,全部加载了,执行语句如下:

Hibernate:     select        person0_.PERSONID as PERSONID3_0_,        person0_.NAME as NAME3_0_,        person0_.SCHOOL as SCHOOL3_0_     from        PERSON person0_     where        person0_.PERSONID=?

  所有普通属性都均已加载。

2、<class lazy=”true”>

  School的lazy属性自然还是true。当程序运行到(4)时,也同样加载了全部属性,执行了如下sql:

Hibernate:     select        person0_.PERSONID as PERSONID3_0_,        person0_.NAME as NAME3_0_,        person0_.SCHOOL as SCHOOL3_0_     from        PERSON person0_     where        person0_.PERSONID=?

  结果就是无效,不管采用何种策略都是无效的,和我们想想的有较大出路。下面是一段来自hibernate官方文档的话。

  Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.(如果你整个类不是lazy=true的话,hibernate会忽视你某个属性的property)

  应该是因为,我们并未用到编译时字节码增强技术的原因。如果只对部分property进行延迟加载的话,hibernate还提供了另外的方式,也是更为推荐的方式,即HQL或者条件查询。

A different way of avoiding unnecessary column reads, at least for read-only transactions, is to use the projection features of HQL or Criteria queries. This avoids the need for buildtime bytecode processing and is certainly a preferred solution.

4 集合无关联

Person类

1publicclass Person {
2private String name;3private String sex;4private Set
addresses;5 }

Person.hbm.xml

1<class name="com.hbm.hibernate.Person" table="PERSON">

   2<id name="name" type="java.lang.String">

   3    <column name="NAME"/>

   4    <generator class="assigned"/>

   5</id>

   6<property name="sex" type="java.lang.String">

   7    <column name="SEX"/>

   8</property>

   9<set name="addresses" table="ADDRESSES" inverse="false" lazy="true" fetch="join">

   10    <key column="NAME"/>

   11    <element column="ADDRESS" type="java.lang.String"></element>

   12</set>

13</class>

4.1 非延迟加载策略

  映射文件的配置<set lazy=”false”>。

1 tx = session.beginTransaction();

2             Person person=(Person) session.load(Person.class, "XiJinping");//(1)

3             System.out.println("");//(2)

4             System.out.println("0: "+person.getName());//(3)

5             System.out.println("1: "+person.getSex());//(4)

6             System.out.println("2: "+person.getAddresses());//(5)

7 tx.commit();

  运行到(4)处时,加载了全部属性,执行了如下sql语句。

1Hibernate:

2/* load com.hbm.hibernate.Person */

select person0_.NAME as NAME0_0_, person0_.SEX as SEX0_0_ from PERSON person0_ where person0_.NAME=?

Hibernate: 10/* load collection com.hbm.hibernate.Person.addresses */

select addresses0_.NAME as NAME0_, addresses0_.ADDRESS as ADDRESS0_ from        ADDRESSES addresses0_ where addresses0_.NAME=?

  fetch策略的配合使用,当<set lazy=”false” fetch=”join”>时,执行的sql语句如下。这个是有,将不再采用两条select语句的方式,而是采用左连接的方式进行,有利于提高效率。

Hibernate:     /* load com.hbm.hibernate.Person */

select        person0_.NAME as NAME0_0_,        person0_.SEX as SEX0_0_,        addresses1_.NAME as NAME2_,        addresses1_.ADDRESS as ADDRESS2_     from        PERSON person0_     leftouterjoin        ADDRESSES addresses1_             on person0_.NAME=addresses1_.NAME     where        person0_.NAME=?

4.2 延迟加载策略

  映射文件的配置<set lazy=”true”>。

  当程序运行到(4),hibernate加载了Person对象的其他全部属性,执行了如下sql语句。

Hibernate:     /* load com.hbm.hibernate.Person */select        person0_.NAME as NAME0_0_,        person0_.SEX as SEX0_0_     from        PERSON person0_     where        person0_.NAME=?

  当程序运行到(5)时,hibernate加载了所有的address对象,执行如下sql语句。

1Hibernate: 2/* load collection com.hbm.hibernate.Person.addresses */select3         addresses0_.NAME as NAME0_,4         addresses0_.ADDRESS as ADDRESS0_ 5from6        ADDRESSES addresses0_ 7where8         addresses0_.NAME=?

4.2 延迟加载extra

It can also be used to enable "extra-lazy" fetching where most operations do not initialize the collection. This is suitable for large collections.

  大部分操作的时候并不会加载集合,适用于大的集合。extra其实是一种比较智能的延迟加载,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条聪明的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据。

      映射文件配置映射文件的配置<set lazy=”extra”>

1publicint getNum(){
2return addresses.size(); 3} 4 5 tx = session.beginTransaction(); 6 Person person=(Person) session.load(Person.class, "XiJinping");//(1) 7 System.out.println("");//(2) 8 System.out.println("0: "+person.getName());//(3) 9 System.out.println("1: "+person.getSex());//(4)10 System.out.println("2: "+person.getNum());//(5)11 System.out.println("3: "+person.getAddresses());//(6)12 tx.commit();

  当程序运行到(4)时,进行了第一次的加载,加载了person对象的所有普通属性,执行sql如下:

Hibernate:     /* load com.hbm.hibernate.Person */select        person0_.NAME as NAME0_0_,        person0_.SEX as SEX0_0_     from        PERSON person0_     where        person0_.NAME=?

  当程序运行到(5)时,进行了第二次加载,这个时候并没有去加载set集合中的所有属性,hibernate智能的用sql语句获取了集合中的数量,执行的sql语句如下:

Hibernate:     selectcount(ADDRESS)     from        ADDRESSES     where        NAME =?

  当程序运行到(6)时,进行了第三次加载,将集合中的所有对象均加载进来了,执行的sql语句如下:

Hibernate:     /* load collection com.hbm.hibernate.Person.addresses */select        addresses0_.NAME as NAME0_,        addresses0_.ADDRESS as ADDRESS0_     from        ADDRESSES addresses0_     where        addresses0_.NAME=?

4.4 总结

  在集合的3中延迟加载中,我觉得最有的配置应该是extra。但是,默认配置false和extra均不适用于,session会话之外的情况。

  Hibernate中集合属性的延迟加载应该来说是最为重要的,因为如果集合属性里面包含十万百万记录,在初始化持久实体的同时,完成所有集合属性的抓取,将导致性能急剧下降。

5 集合有关联

Person类

1publicclass Person {
2private String personId;3private String name;4private Set addresses;5publicint getNum(){
6return addresses.size();7    }8 }

Address类

1publicclass Address {
2private String addressId;3private String addressDetail;4private Set people;5 }

Person.hbm.xml

………        

5.1 非延迟加载

  映射文件配置<set lazy=”false”>

1 tx = session.beginTransaction();2 Person person=(Person) session.load(Person.class, "001");//(1)3 System.out.println("");//(2)4 System.out.println("0: "+person.getPersonId());//(3)5 System.out.println("1: "+person.getName());//(4)6 System.out.println("2: "+person.getNum());//(5)7 System.out.println("3: "+person.getAddresses());//(6)8 tx.commit();

  当程序运行到(4)时,hibernate加载了所有属性,执行的sql语句如下:

Hibernate:     select        person0_.PERSONID as PERSONID2_0_,        person0_.NAME as NAME2_0_     from        PERSON person0_     where        person0_.PERSONID=?Hibernate:     select        addresses0_.PERSONID as PERSONID1_,        addresses0_.ADDRESSID as ADDRESSID1_,        address1_.ADDRESSID as ADDRESSID0_0_,        address1_.ADDRESSDETAIL as ADDRESSD2_0_0_     from        PERSON_ADDRESS addresses0_     leftouterjoin        ADDRESS address1_             on addresses0_.ADDRESSID=address1_.ADDRESSID     where        addresses0_.PERSONID=?

5.2 延迟加载与extra策略

  与无关联关系时一致,不再累述。

6 1-1和N-1延迟加载策略

LineItem类

publicclass LineItem {    privateint lineNumber;    privateint amount;    privatedouble price;private Product product;}

Product类

publicclass Product {    private String id;    private String name;privatedouble listprice;}

LineItem.hbm.xml

6.1 非延迟加载

  映射文件配置<many-to-one lazy=”false”>

1 tx = session.beginTransaction();2 LineItem l=(LineItem) session.load(LineItem.class, 2);//(1)3 System.out.println("");//(2)4 System.out.println("0: "+l.getLineNumber());//(3)5 System.out.println("1: "+l.getAmount());//(4)6 System.out.println("2: "+l.getProduct());//(5)7 tx.commit();

  程序运行到(4)处时,hibernate加载了所有属性,执行了如下sql语句:

Hibernate:     select        lineitem0_.LINENUMBER as LINENUMBER1_0_,        lineitem0_.AMOUNT as AMOUNT1_0_,        lineitem0_.PRICE as PRICE1_0_,        lineitem0_1_.PRODUCTID as PRODUCTID2_0_     from        LINEITEM lineitem0_     innerjoin        LINE_PRODUCT lineitem0_1_             on lineitem0_.LINENUMBER=lineitem0_1_.LINENUMBER     where        lineitem0_.LINENUMBER=?Hibernate:     select        product0_.PRODUCTID as PRODUCTID0_0_,        product0_.NAME as NAME0_0_,        product0_.LISTPRICE as LISTPRICE0_0_     from        PRODUCT product0_     where        product0_.PRODUCTID=?

  在这个时候,去查看内存中的LineItem类型对象,我们发现也是一个代理类。而回调函数中,tagert属性中的Prdouct是一个真正的Product类型对象。

11111108-a3af66c29c874919aced404ec7d1577

6.2 延迟加载proxy

   映射文件设置<many-to-one lazy=”proxy”>

      当程序运行到(4)时,进行了第一次的加载,执行的sql语句如下:

Hibernate:     select        lineitem0_.LINENUMBER as LINENUMBER1_0_,        lineitem0_.AMOUNT as AMOUNT1_0_,        lineitem0_.PRICE as PRICE1_0_,        lineitem0_1_.PRODUCTID as PRODUCTID2_0_     from        LINEITEM lineitem0_     innerjoin        LINE_PRODUCT lineitem0_1_             on lineitem0_.LINENUMBER=lineitem0_1_.LINENUMBER     where        lineitem0_.LINENUMBER=?

  当程序运行到(5)时,进行了第二次的加载,执行的sql语句如下:

Hibernate:     select        product0_.PRODUCTID as PRODUCTID0_0_,        product0_.NAME as NAME0_0_,        product0_.LISTPRICE as LISTPRICE0_0_     from        PRODUCT product0_     where        product0_.PRODUCTID=?

  这个时候,我们去参看内存,发现target中的product属性便是个代理类,如下图所示:

11111257-08c2660cea674856b0c2807bc03b26a

6.3 总结

  默认情况下,Hibernate 也会采用延迟加载来加载关联实体,不管是一对多关联、还是一对一关联、多对多关联,Hibernate 默认都会采用延迟加载。

  对于关联实体,可以将其分为两种情况:

  关联实体是多个实体时(包括一对多、多对多):此时关联实体将以集合的形式存在,Hibernate 将使用 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合来管理延迟加载的实体。这就是前面所介绍的情形。

  关联实体是单个实体时(包括一对一、多对一):当 Hibernate 加载某个实体时,延迟的关联实体将是一个动态生成代理对象。

  当关联实体是单个实体时,也就是使用 <many-to-one.../> 或 <one-to-one.../> 映射关联实体的情形,这两个元素也可通过 lazy 属性来指定延迟加载。

7 继承(subclass为例)

Payment类

1publicclass Payment {
2privatelong id;3privatelong amount;4 }

CreditCardPayment类

publicclass CreditCardPayment extends Payment {    privatelong creditId;private String cardType;}

creditCardPayment.hbm.xml

8.1 非延迟加载

  映射文件配置<subclass lazy=”false”>。

1 tx = session.beginTransaction();2 CreditCardPayment ccp=(CreditCardPayment) session.load(CreditCardPayment.class,new Long(8889));//(1)3 System.out.println("");//(2)4 System.out.println("0: "+ccp.getId());//(3)5 System.out.println("1: "+ccp.getAmount());//(4)6 System.out.println("2: "+ccp.getCardType());//(5)7 tx.commit();

  程序运行到(1)时,加载全部属性,执行的sql语句如下:

Hibernate:     select        creditcard0_.ID as ID0_0_,        creditcard0_.AMOUNT as AMOUNT0_0_,        creditcard0_.CREDITID as CREDITID0_0_,        creditcard0_.CARDTYPE as CARDTYPE0_0_     from        PAYMENT creditcard0_     where        creditcard0_.ID=?         and creditcard0_.PAYMENT_TYPE='CREDIT'

7.2 延迟加载

  映射文件配置<subclass lazy=”true”>

Hibernate:     select        creditcard0_.ID as ID0_0_,        creditcard0_.AMOUNT as AMOUNT0_0_,        creditcard0_.CREDITID as CREDITID0_0_,        creditcard0_.CARDTYPE as CARDTYPE0_0_     from        PAYMENT creditcard0_     where        creditcard0_.ID=?         and creditcard0_.PAYMENT_TYPE='CREDIT'

  程序执行到(4)时,第一次加载全部属性,执行的sql语句如上。

7.3 总结

  继承方式的延迟加载,set等在true或false时并未显著差别,在这里不再累述。