您的位置:首页 > 其它

Hibernate 延迟加载(二)

2014-01-24 14:39 211 查看

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<String> 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
<class name="com.hbm.hibernate.Person" table="PERSON">………        <set name="addresses" table="PERSON_ADDRESS" cascade="all"><key><column name="PERSONID"/></key><many-to-many class="com.hbm.hibernate.Address" column="ADDRESSID"></many-to-many></set></class>

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
<class name="com.hbm.hibernate.LineItem" table="LINEITEM"><id name="lineNumber" type="int"><column name="LINENUMBER"/><generator class="assigned"/></id><property name="amount" type="int"><column name="AMOUNT"/></property><property name="price" type="double"><column name="PRICE"/></property><join table="LINE_PRODUCT"><key column="LINENUMBER"/><many-to-one name="product" unique="true" lazy="false" not-null="true" column="PRODUCTID"/></join></class>

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类型对象。

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属性便是个代理类,如下图所示:

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
<subclass name="com.hbm.hibernate.CreditCardPayment" discriminator-value="CREDIT"        extends="com.hbm.hibernate.Payment" lazy="false"><property name="creditId" column="CREDITID" type="long"></property><property name="cardType" column="CARDTYPE" type="java.lang.String"></property></subclass>

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时并未显著差别,在这里不再累述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: