H*ber*ate Lazy属性

1 延迟加载策略

  H*ber*ate 的延迟加载(lazy load)是一个被广泛使用的技术。这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录。通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销。H*ber*ate 的延迟加载本质上就是代理模式的应用,当程序通过 H*ber*ate 装载一个实体时,默认情况下,H*ber*ate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势。

  但是,延迟加载也是项目开发中特别常见的一个错误。如果对一个类或者集合配置了延迟检索策略,那么必须当代理类实例或代理集合处于持久化状态(即处于Sess*o*范围内)时,才能初始化它。如果在游离状态时才初始化它,就会产生延迟初始化错误。所以,在开发独立的DAO数据访问层时应该格外小心这个问题。

  如果在获取对象的时候使用的是sess*o*.*et()是不会延迟加载的,只有在使用load、hql时候才会延迟加载。

&*bsp;&*bsp;&*bsp;&*bsp;&*bsp;&*bsp; H*ber*ate中允许使用延迟加载的地方主要有以下几个地方:

<h*ber*ate-mapp*** default-lazy=(true|false)”true”&*t;:设置全局的延迟加载策略。

<class lazy=(true|false)&*t;:DTD没设置默认值,推理默认值为true

<property lazy=(true|false)&*t;:设置字段延迟加载,默认为false

<compo*e*t lazy=(true|false):默认为false

<subclass lazy=(true|false)&*t;:默认设置为true

<jo**-subclass lazy=(true|false)&*t;:默认设置为true

<u**o*-subclass lazy=(true|false)&*t;:默认设置为true

<ma*y-to-o*e lazy=(proxy|*o-proxy|false)&*t;:默认为proxy

<o*e-to-o*e lazy=(proxy|*o-proxy|false)&*t;:默认为proxy

<map lazy=(true|extra|false)&*t;:默认为true

<set lazy=(true|extra|false)&*t;:默认为true

<ba* lazy=(true|extra|false)&*t;:默认为true

<*ba* lazy=(true|extra|false)&*t;:默认为true

<l*st lazy=(true|extra|false)&*t;:默认为true

&*bsp;

2 对象加载<class&*t;

2.1 延迟加载策略(默认)

  如果想对实体对象使用延迟加载,必须要在实体的映射配置文件中进行相应的配置

  <class *ame="*erso*" table="*ERSON" lazy="true"&*t;

1     tx = sess*o*.be***Tra*sact*o*();
2     *erso* p=(*erso*) sess*o*.load(*erso*.class, "001");//(1)
3     System.out.pr**tl*("0: "+p.*et*erso*Id());//(2)
4     System.out.pr**tl*("0: "+p.*etName());//(3)
5 tx.comm*t();
6     sess*o*.close();

  执行到(1)并没有出现sql语句,并没有从数据库中抓取数据。这个时候查看内存对象p如下:

<*m* style="d*splay: block; mar***-left: auto; mar***-r**ht: auto;" src="http://*ma*es.c**tblo*.com/blo*/440394/201306/11104312-77430cb248e647f1b4ba9377bfbf4814.p**" alt="" />

图2.1 perso*对象load时的内存快照

  观察perso*对象,我们可发现是*erso*$$E*ha*cerBy..的类型的对象。这里所返回的对象类型就是*erso*对象的代理对象,在h*ber*ate中通过使用CGLB来先动态构造一个目标对象的代理类对象,并且在代理对象中包含目标对象的所有属性和方法。所以,对于客户端而言是否为代理类是无关紧要的,对他来说是透明的。这个对象中,仅仅设置了*d属性(即perso*Id的值),这是为了便于后面根据这个Id从数据库中来获取数据。

&*bsp;&*bsp; 运行到(2)处,输出为001,但是仍然没有从数据库里面读取数据。这个时候代理类的作用就体现出来了,客户端觉得perso*类已经实现了(事实上并未创建)。但是,如果这个会后sess*o*关闭,再使用perso*对象就会出错了。

&*bsp;&*bsp; 调试运行到(3)处,要用到*ame属性,但是这个值在数据库中。所以h*ber*ate从数据库里面抓取了数据,sql语句如下所示:

H*ber*ate: 
    select
        perso*0_.*ERSONID as *ERSONID3_0_,
        perso*0_.NAME as NAME3_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.*ERSONID=?

  这时候,我们查看内存里面的对象如下:

<*m* style="d*splay: block; mar***-left: auto; mar***-r**ht: auto;" src="http://*ma*es.c**tblo*.com/blo*/440394/201306/11104449-1954ccae56e148d5b90bad85a13fc4e3.p**" alt="" />

图2.2 class延迟加载时内存对象

  真正的*erso*对象放在CGLIB$CALLBACK_0对象中的tar*et属性里。

  这样,通过一个中间代理对象,H*ber*ate实现了实体的延迟加载,只有当用户真正发起获得实体对象属性的动作时,才真正会发起数据库查询操作。所以实体的延迟加载是用通过中间代理类完成的,所以只有sess*o*.load()方法才会利用实体延迟加载,因为只有sess*o*.load()方法才会返回实体类的代理类对象。

2.2 非延迟加载策略

  H*ber*ate默认的策略便是非延迟加载的,所以设置lazy=false

  

1     tx = sess*o*.be***Tra*sact*o*();
2     *erso* p=(*erso*) sess*o*.load(*erso*.class, "001");//(1)
3     System.out.pr**tl*("0: "+p.*et*erso*Id());//(2)
4     System.out.pr**tl*("0: "+p.*etName());//(3)
5     tx.comm*t();
6     sess*o*.close();

  调试运行到(1)处时,h*ber*ate直接执行如下sql语句:

H*ber*ate: 
    select
        perso*0_.*ERSONID as *ERSONID3_0_,
        perso*0_.NAME as NAME3_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.*ERSONID=?

  我们在查看内存快照如下:

<*m* style="d*splay: block; mar***-left: auto; mar***-r**ht: auto;" src="http://*ma*es.c**tblo*.com/blo*/440394/201306/11104806-f36d698286c94c45abbbb6a8d074c381.p**" alt="" />

&*bsp; &*bsp; &*bsp; 这个时候就不是一个代理类了,而是*erso*对象本身了。里面的属性也已经全部普通属性也全部被加载。这里说普通属性是因为addresses这个集合对象并没有被加载,因为set自己本身也可以设置lazy属性。所以,这里也反映出class对象的lazy并不能控制关联或集合的加载策略。

2.3 总结

  H*ber*ate中<class lazy=””&*t;默认为true。如果,在load的时候只会返回一个代理类,并不会正在从数据库中读取数据。第一次用到时,会将所有普通属性(set这种就不是)全部加载进来。如果第一次使用到时,sess*o*已经关闭将发生错误。

  如果显式是设置lazy=false,load的时候即会把所有普通属性全部读取进来。而且,返回的将是一个真正的该类型的对象(如*erso*),而不是代理类。

3 字段加载(property)

  在H*ber*ate3中,引入了一种新的特性——属性的延迟加载,这个机制又为获取高性能查询提供了有力的工具。在大数据对象读取时,如*erso*对象中有一个School字段,该字段是一个java.sql.Clob类型,包含了用户的简历信息,当我们加载该对象时,我们不得不每一次都要加载这个字段,而不论我们是否真的需要它,而且这种大数据对象的读取本身会带来很大的性能开销。

3.1 延迟加载

1、 &*bsp;<class lazy=”false”&*t;

  配置如下

1     tx = sess*o*.be***Tra*sact*o*();
2     *erso* p=(*erso*) sess*o*.load(*erso*.class, "001");//(1)
3     System.out.pr**tl*("");//(2)
4     System.out.pr**tl*("0: "+p.*et*erso*Id());//(3)
5     System.out.pr**tl*("0: "+p.*etName());//(4)
6     System.out.pr**tl*("0: "+p.*etSchool());//(5)
7     tx.comm*t();
1         <property *ame="*ame" type="java.la**.Str***"&*t;
2             <colum* *ame="NAME" /&*t;
3         </property&*t;
4         <property *ame="school" type="java.la**.Str***" lazy="true"&*t;
5             <colum* *ame="SCHOOL"&*t;</colum*&*t;
6     </property&*t;

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

H*ber*ate: 
    select
        perso*0_.*ERSONID as *ERSONID3_0_,
        perso*0_.NAME as NAME3_0_,
        perso*0_.SCHOOL as SCHOOL3_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.*ERSONID=?

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

2、<class lazy=”true”&*t;

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

H*ber*ate: 
    select
        perso*0_.*ERSONID as *ERSONID3_0_,
        perso*0_.NAME as NAME3_0_,
        perso*0_.SCHOOL as SCHOOL3_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.*ERSONID=?

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

  Lazy property load*** requ*res bu*ldt*me bytecode **strume*tat*o*. If your pers*ste*t classes are *ot e*ha*ced, H*ber*ate w*ll ***ore lazy property sett***s a*d retur* to *mmed*ate fetch***.

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

  A d*ffere*t way of avo*d*** u**ecessary colum* reads, at least for read-o*ly tra*sact*o*s, *s to use the project*o* features of HQL or Cr*ter*a quer*es. Th*s avo*ds the *eed for bu*ldt*me bytecode process*** a*d *s certa**ly a preferred solut*o*.

4 集合无关联

*erso*类

1 publ*c class *erso* {
2     pr*vate Str*** *ame;
3     pr*vate Str*** sex;
4 pr*vate Set<Str***&*t; addresses;
5 }

*erso*.hbm.xml

 1 <class *ame="com.hbm.h*ber*ate.*erso*" table="*ERSON"&*t;
 2         <*d *ame="*ame" type="java.la**.Str***"&*t;
 3             <colum* *ame="NAME"/&*t;
 4             <*e*erator class="ass***ed"/&*t;
 5         </*d&*t;
 6         <property *ame="sex" type="java.la**.Str***"&*t;
 7             <colum* *ame="SE*"/&*t;
 8         </property&*t;
 9         <set *ame="addresses" table="ADDRESSES" **verse="false" lazy="true" fetch="jo**"&*t;
10             <key colum*="NAME"/&*t;
11             <eleme*t colum*="ADDRESS" type="java.la**.Str***"&*t;</eleme*t&*t;
12         </set&*t;
13 </class&*t;

4.1 非延迟加载策略

  映射文件的配置<set lazy=”false”&*t;。

1        tx = sess*o*.be***Tra*sact*o*();
2             *erso* perso*=(*erso*) sess*o*.load(*erso*.class, "*****p***");//(1)
3             System.out.pr**tl*("");//(2)
4             System.out.pr**tl*("0: "+perso*.*etName());//(3)
5             System.out.pr**tl*("1: "+perso*.*etSex());//(4)
6             System.out.pr**tl*("2: "+perso*.*etAddresses());//(5)
7            tx.comm*t();

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

 1 H*ber*ate: 
 2     /* load com.hbm.h*ber*ate.*erso* */ select
 3         perso*0_.NAME as NAME0_0_,
 4         perso*0_.SE* as SE*0_0_ 
 5     from
 6         *ERSON perso*0_ 
 7     where
 8         perso*0_.NAME=?
 9 H*ber*ate: 
10     /* load collect*o* com.hbm.h*ber*ate.*erso*.addresses */ select
11         addresses0_.NAME as NAME0_,
12         addresses0_.ADDRESS as ADDRESS0_ 
13     from
14         ADDRESSES addresses0_ 
15     where
16     addresses0_.NAME=?

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

H*ber*ate: 
    /* load com.hbm.h*ber*ate.*erso* */ select
        perso*0_.NAME as NAME0_0_,
        perso*0_.SE* as SE*0_0_,
        addresses1_.NAME as NAME2_,
        addresses1_.ADDRESS as ADDRESS2_ 
    from
        *ERSON perso*0_ 
    left outer jo**
        ADDRESSES addresses1_ 
            o* perso*0_.NAME=addresses1_.NAME 
    where
        perso*0_.NAME=?

4.2 延迟加载策略

  映射文件的配置<set lazy=”true”&*t;。

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

H*ber*ate: 
    /* load com.hbm.h*ber*ate.*erso* */ select
        perso*0_.NAME as NAME0_0_,
        perso*0_.SE* as SE*0_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.NAME=?

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

1 H*ber*ate: 
2     /* load collect*o* com.hbm.h*ber*ate.*erso*.addresses */ select
3         addresses0_.NAME as NAME0_,
4         addresses0_.ADDRESS as ADDRESS0_ 
5     from
6         ADDRESSES addresses0_ 
7     where
8         addresses0_.NAME=?

4.2 延迟加载extra

  It ca* also be used to e*able "extra-lazy" fetch*** where most operat*o*s do *ot ***t*al*ze the collect*o*. Th*s *s su*table for lar*e collect*o*s.

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

&*bsp;&*bsp;&*bsp;&*bsp;&*bsp;&*bsp; 映射文件配置映射文件的配置<set lazy=”extra”&*t;

  

 1 publ*c **t *etNum(){
 2         retur* addresses.s*ze();
 3 }
 4 
 5 tx = sess*o*.be***Tra*sact*o*();
 6 *erso* perso*=(*erso*) sess*o*.load(*erso*.class, "*****p***");//(1)
 7 System.out.pr**tl*("");//(2)
 8 System.out.pr**tl*("0: "+perso*.*etName());//(3)
 9 System.out.pr**tl*("1: "+perso*.*etSex());//(4)
10 System.out.pr**tl*("2: "+perso*.*etNum());//(5)
11 System.out.pr**tl*("3: "+perso*.*etAddresses());//(6)
12 tx.comm*t();

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

H*ber*ate: 
    /* load com.hbm.h*ber*ate.*erso* */ select
        perso*0_.NAME as NAME0_0_,
        perso*0_.SE* as SE*0_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.NAME=?

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

H*ber*ate: 
    select
        cou*t(ADDRESS) 
    from
        ADDRESSES 
    where
        NAME =?

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

H*ber*ate: 
    /* load collect*o* com.hbm.h*ber*ate.*erso*.addresses */ select
        addresses0_.NAME as NAME0_,
        addresses0_.ADDRESS as ADDRESS0_ 
    from
        ADDRESSES addresses0_ 
    where
        addresses0_.NAME=?

4.4 总结

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

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

5 集合有关联

*erso*类

1 publ*c class *erso* {
2     pr*vate Str*** perso*Id;
3     pr*vate Str*** *ame;
4 pr*vate Set addresses;
5     publ*c **t *etNum(){
6         retur* addresses.s*ze();
7     }
8 }

Address类

1 publ*c class Address {
2     pr*vate Str*** addressId;
3     pr*vate Str*** addressDeta*l;
4 pr*vate Set people;
5 }

*erso*.hbm.xml

<class *ame="com.hbm.h*ber*ate.*erso*" table="*ERSON"&*t;
&hell*p;&hell*p;&hell*p;
        <set *ame="addresses" table="*ERSON_ADDRESS" cascade="all"&*t;
            <key&*t;
                <colum* *ame="*ERSONID" /&*t;
            </key&*t;
            <ma*y-to-ma*y class="com.hbm.h*ber*ate.Address" colum*="ADDRESSID"&*t;</ma*y-to-ma*y&*t;
        </set&*t;
 </class&*t;

5.1 非延迟加载

  映射文件配置<set lazy=”false”&*t;

1 tx = sess*o*.be***Tra*sact*o*();
2 *erso* perso*=(*erso*) sess*o*.load(*erso*.class, "001");//(1)
3 System.out.pr**tl*("");//(2)
4 System.out.pr**tl*("0: "+perso*.*et*erso*Id());//(3)
5 System.out.pr**tl*("1: "+perso*.*etName());//(4)
6 System.out.pr**tl*("2: "+perso*.*etNum());//(5)
7 System.out.pr**tl*("3: "+perso*.*etAddresses());//(6)
8 tx.comm*t();

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

H*ber*ate: 
    select
        perso*0_.*ERSONID as *ERSONID2_0_,
        perso*0_.NAME as NAME2_0_ 
    from
        *ERSON perso*0_ 
    where
        perso*0_.*ERSONID=?
H*ber*ate: 
    select
        addresses0_.*ERSONID as *ERSONID1_,
        addresses0_.ADDRESSID as ADDRESSID1_,
        address1_.ADDRESSID as ADDRESSID0_0_,
        address1_.ADDRESSDETAIL as ADDRESSD2_0_0_ 
    from
        *ERSON_ADDRESS addresses0_ 
    left outer jo**
        ADDRESS address1_ 
            o* addresses0_.ADDRESSID=address1_.ADDRESSID 
    where
        addresses0_.*ERSONID=?

5.2 延迟加载与extra策略

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

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

L**eItem类

publ*c class L**eItem {
    pr*vate **t l**eNumber;
    pr*vate **t amou*t;
    pr*vate double pr*ce;
pr*vate *roduct product;
}

*roduct类

publ*c class *roduct {
    pr*vate Str*** *d;
    pr*vate Str*** *ame;
pr*vate double l*stpr*ce;
}

L**eItem.hbm.xml

    <class *ame="com.hbm.h*ber*ate.L**eItem" table="LINEITEM"&*t;
        <*d *ame="l**eNumber" type="**t"&*t;
            <colum* *ame="LINENUMBER" /&*t;
            <*e*erator class="ass***ed" /&*t;
        </*d&*t;
        <property *ame="amou*t" type="**t"&*t;
            <colum* *ame="AMOUNT" /&*t;
        </property&*t;
        <property *ame="pr*ce" type="double"&*t;
            <colum* *ame="*RICE" /&*t;
        </property&*t;
        <jo** table="LINE_*RODUCT"&*t;
            <key colum*="LINENUMBER"/&*t;
            <ma*y-to-o*e *ame="product" u**que="true" lazy="false" *ot-*ull="true" colum*="*RODUCTID"/&*t;
        </jo**&*t;
 </class&*t;

6.1 非延迟加载

  映射文件配置<ma*y-to-o*e lazy=”false”&*t;

1 tx = sess*o*.be***Tra*sact*o*();
2 L**eItem l=(L**eItem) sess*o*.load(L**eItem.class, 2);//(1)
3 System.out.pr**tl*("");//(2)
4 System.out.pr**tl*("0: "+l.*etL**eNumber());//(3)
5 System.out.pr**tl*("1: "+l.*etAmou*t());//(4)
6 System.out.pr**tl*("2: "+l.*et*roduct());//(5)
7 tx.comm*t();

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

H*ber*ate: 
    select
        l**e*tem0_.LINENUMBER as LINENUMBER1_0_,
        l**e*tem0_.AMOUNT as AMOUNT1_0_,
        l**e*tem0_.*RICE as *RICE1_0_,
        l**e*tem0_1_.*RODUCTID as *RODUCTID2_0_ 
    from
        LINEITEM l**e*tem0_ 
    ***er jo**
        LINE_*RODUCT l**e*tem0_1_ 
            o* l**e*tem0_.LINENUMBER=l**e*tem0_1_.LINENUMBER 
    where
        l**e*tem0_.LINENUMBER=?
H*ber*ate: 
    select
        product0_.*RODUCTID as *RODUCTID0_0_,
        product0_.NAME as NAME0_0_,
        product0_.LIST*RICE as LIST*RICE0_0_ 
    from
        *RODUCT product0_ 
    where
        product0_.*RODUCTID=?

  在这个时候,去查看内存中的L**eItem类型对象,我们发现也是一个代理类。而回调函数中,ta*ert属性中的*rdouct是一个真正的*roduct类型对象。

<*m* style="d*splay: block; mar***-left: auto; mar***-r**ht: auto;" src="http://*ma*es.c**tblo*.com/blo*/440394/201306/11111108-a3af66c29c874919aced404ec7d1577b.p**" alt="" />

6.2 延迟加载proxy

  &*bsp;映射文件设置<ma*y-to-o*e lazy=”proxy”&*t;

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

H*ber*ate: 
    select
        l**e*tem0_.LINENUMBER as LINENUMBER1_0_,
        l**e*tem0_.AMOUNT as AMOUNT1_0_,
        l**e*tem0_.*RICE as *RICE1_0_,
        l**e*tem0_1_.*RODUCTID as *RODUCTID2_0_ 
    from
        LINEITEM l**e*tem0_ 
    ***er jo**
        LINE_*RODUCT l**e*tem0_1_ 
            o* l**e*tem0_.LINENUMBER=l**e*tem0_1_.LINENUMBER 
    where
        l**e*tem0_.LINENUMBER=?

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

H*ber*ate: 
    select
        product0_.*RODUCTID as *RODUCTID0_0_,
        product0_.NAME as NAME0_0_,
        product0_.LIST*RICE as LIST*RICE0_0_ 
    from
        *RODUCT product0_ 
    where
        product0_.*RODUCTID=?

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

<*m* style="d*splay: block; mar***-left: auto; mar***-r**ht: auto;" src="http://*ma*es.c**tblo*.com/blo*/440394/201306/11111257-08c2660cea674856b0c2807bc03b26a0.p**" alt="" />

6.3 总结

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

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

  关联实体是多个实体时(包括一对多、多对多):此时关联实体将以集合的形式存在,H*ber*ate 将使用 *ers*ste*tSet、*ers*ste*tL*st、*ers*ste*tMap、*ers*ste*tSortedMap、*ers*ste*tSortedSet 等集合来管理延迟加载的实体。这就是前面所介绍的情形。

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

  当关联实体是单个实体时,也就是使用 <ma*y-to-o*e.../&*t; 或 <o*e-to-o*e.../&*t; 映射关联实体的情形,这两个元素也可通过 lazy 属性来指定延迟加载。

7 继承(subclass为例)

*ayme*t类

1 publ*c class *ayme*t {
2     pr*vate lo** *d;
3 pr*vate lo** amou*t;
4 }

Cred*tCard*ayme*t类

publ*c class Cred*tCard*ayme*t exte*ds *ayme*t {
    pr*vate lo** cred*tId;
pr*vate Str*** cardType;
}

cred*tCard*ayme*t.hbm.xml

    <subclass *ame="com.hbm.h*ber*ate.Cred*tCard*ayme*t" d*scr*m**ator-value="CREDIT"
        exte*ds="com.hbm.h*ber*ate.*ayme*t" lazy="false"&*t;
        <property *ame="cred*tId" colum*="CREDITID" type="lo**"&*t;</property&*t;
        <property *ame="cardType" colum*="CARDTY*E" type="java.la**.Str***"&*t;</property&*t;
    </subclass&*t;

8.1 非延迟加载

  映射文件配置<subclass lazy=”false”&*t;。

  

1 tx = sess*o*.be***Tra*sact*o*();
2 Cred*tCard*ayme*t ccp=(Cred*tCard*ayme*t) sess*o*.load(Cred*tCard*ayme*t.class,*ew Lo**(8889));//(1)
3 System.out.pr**tl*("");//(2)
4 System.out.pr**tl*("0: "+ccp.*etId());//(3)
5 System.out.pr**tl*("1: "+ccp.*etAmou*t());//(4)
6 System.out.pr**tl*("2: "+ccp.*etCardType());//(5)
7 tx.comm*t();

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

H*ber*ate: 
    select
        cred*tcard0_.ID as ID0_0_,
        cred*tcard0_.AMOUNT as AMOUNT0_0_,
        cred*tcard0_.CREDITID as CREDITID0_0_,
        cred*tcard0_.CARDTY*E as CARDTY*E0_0_ 
    from
        *AYMENT cred*tcard0_ 
    where
        cred*tcard0_.ID=? 
        a*d cred*tcard0_.*AYMENT_TY*E='CREDIT'

7.2 延迟加载

  映射文件配置<subclass lazy=”true”&*t;

H*ber*ate: 
    select
        cred*tcard0_.ID as ID0_0_,
        cred*tcard0_.AMOUNT as AMOUNT0_0_,
        cred*tcard0_.CREDITID as CREDITID0_0_,
        cred*tcard0_.CARDTY*E as CARDTY*E0_0_ 
    from
        *AYMENT cred*tcard0_ 
    where
        cred*tcard0_.ID=? 
        a*d cred*tcard0_.*AYMENT_TY*E='CREDIT'

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

7.3 总结

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

&*bsp;

参考文献

1、http://docs.jboss.or*/h*ber*ate/orm/4.2/ma*ual/e*-US/html_s***le/

2、http://blo*.163.com/x*_zh_q*/blo*/stat*c/8501594200812695053939/

3、http://blo*.csd*.*et/l**x***hu*/art*cle/deta*ls/3862324

4、http://www.*bm.com/developerworks/c*/java/j-lo-h*ber*atelazy/

原文地址:https://www.cnblogs.com/wukenaihe/p/3131640.html