hibernate lazy(延遲加載)

hibernate lazy策略可使用在:
* <class>標籤上,能夠取值:true/false ,在hibernate3以上版本,默認是true
* <property>標籤上,能夠取值:true/false須要類加強工具
* <set><list>標籤上,能夠取值:true/false/extra
* <one-to-one><many-to-one>單端關聯上,能夠取值:false/proxy/no-proxy

lazy概念:只有真正使用該對象時,纔會建立,對於hibernate而言,正真使用的時候纔會發出sqljava

hibernate支持lazy策略只有在session打開狀態下有效sql

=====================================================數據庫

1. <class>標籤上:session

hbmapp

group.hbm.xml工具

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.model">
    <class name="Group" table="group5" lazy="true" > //lazy,默認true,可不寫
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native" />         
        </id>
        <property name="name" column="name" length="50" type="java.lang.String" />
       
    </class>

</hibernate-mapping>
測試

測試用例:fetch

public class LazyTest extends TestCase {

public void testLoad1(){
   Session session = null;
   Transaction ta = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
this

    Group g2 = (Group) session.load(Group.class, 1); //還沒發出sql,lazy起延遲做用,若lazy=false,則發出sql
//    Group g2 = (Group) session.get(Group.class, 1); //不支持lazy
    System.out.println("group.id=" + g2.getId()); //還沒發出sql,
    System.out.println("group.name=" + g2.getName()); //發出sql
    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    if(ta != null){
     ta.rollback();
    }
   }finally{
    //關閉session, user變爲detached離線對象
    HibernateUtil.closeSession(session);
   }
   //System.out.println("group.name=" + g2.getName()); //hibernate支持lazy策略只有在session打開狀態下有效,因此此出Exception
}
spa

}

<class>標籤上的lazy特性只對普通屬性起做用

<class>標籤上的lazy不會影響到單端關聯上的lazy特性

=========================================

2.<set><list>標籤上,能夠取值:true/false/extra,默認是true

hbm.xml

Classes.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zd.model">
    <class name="Classes" table="classes" >
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native" />
        </id>
        <property name="name" column="name" type="java.lang.String" />
       <set name="students" lazy="true"> //可不配lazy,因默認是true
            <key column="class_id" />
            <one-to-many class="com.zd.model.Student" />
        </set>
    </class>

</hibernate-mapping>

測試用例:

public void testLoad1(){
   Session session = null;
   Transaction ta = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
    Classes c = (Classes) session.load(Classes.class, new Integer(2)); //沒有sql
    System.out.println("Class.name=" + c.getName());//發出一條sql,但不查 set
    Set stuSet = c.getStudents();//沒有發出查詢sql,不是統計sql
    //System.out.println(stuSet.size());//發出查詢sqlsql
    if(stuSet != null && !stuSet.isEmpty()){//發出查詢sqlsql
     for(Iterator it = stuSet.iterator(); it.hasNext();){
      Student s = (Student) it.next();//若沒有.size(),isEmpty(),就在這邊發出sql
      System.out.println("student.name=" + s.getName());
     }
    }
    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    if(ta != null){
     ta.rollback();
    }
   }finally{
    //關閉session, user變爲detached離線對象
    HibernateUtil.closeSession(session);
   }
  
}

Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?
Class.name=Java Class
Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id=?
2
student.name=z3
student.name=l4

<set name="students" lazy="false"> //不延遲加載, 立刻加載

則在

System.out.println("Class.name=" + c.getName());// 就發出2條查詢語句了。

Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?
Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id=?
Class.name=Java Class
student.name=l4
student.name=z3

<set name="students" lazy="extra"> //和true差很少,只是在寫set.size()時,發出selcet count的sql語句,比true好一些。

測試用例:

public void testLoad1(){
   Session session = null;
   Transaction ta = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
    Classes c = (Classes) session.load(Classes.class, new Integer(2));
    System.out.println("Class.name=" + c.getName());
    Set stuSet = c.getStudents();
   System.out.println(stuSet.size());
    if(stuSet != null && !stuSet.isEmpty()){
     for(Iterator it = stuSet.iterator(); it.hasNext();){
      Student s = (Student) it.next();
      System.out.println("student.name=" + s.getName());
     }
    }
    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    if(ta != null){
     ta.rollback();
    }
   }finally{
    //關閉session, user變爲detached離線對象
    HibernateUtil.closeSession(session);
   }
  
}

Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?
Class.name=Java Class
Hibernate: select count(id) from student where class_id =?
2
Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from student students0_ where students0_.class_id=?
student.name=z3
student.name=l4

===============================================

3.<one-to-one><many-to-one>單端關聯上,能夠取值:false/proxy/no-proxy,默認是proxy(代理),延遲加載做用

hbm.xml

User.hbm.xml 多的一端

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.model">
    <class name="User" table="user1" >
        <id name="id" column="user_id" type="java.lang.Integer">
            <generator class="native" />
        </id>
        <property name="name" length="50" type="java.lang.String" />
        <many-to-one name="group" column="group_id" lazy="proxy"></many-to-one> //可不寫,默認是proxy
    </class>

</hibernate-mapping>

測試用例:

public void testGet1(){
   Session session = null;
   Transaction ta = null;
   User user = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
    user = (User)session.load(User.class, new Integer(3)); //無sql
    System.out.println("user.name=" + user.getName()); //有一條sql
    Group group = user.getGroup();//無sql
    System.out.println("group.name=" + group.getName());//有一條sql
    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    ta.rollback();
   }finally{
    //關閉session, user變爲detached離線對象
    HibernateUtil.closeSession(session);
   }
  
}

若<many-to-one name="group" column="group_id" lazy="false"></many-to-one>

不延遲加載,當即加載,

System.out.println("user.name=" + user.getName()); //發出2條sql語句

==========================================

hibernate 中的 lazy="proxy" 和 lazy="no-proxy" 究竟是什麼意思?

舉個例子吧:
Child <- many-to-one ->Parent

class Child {
private Parent parent;

public Parent getParent (){
return this.parent;//訪問了實例變量
}

}

class Parent {
private String name;

public String getName(){
return this.name;//訪問了實例變量
}

public void f(){
System.out.println("invokeing f()");//沒有訪問實例變量
}
}

若是
many-to-one 的lazy設爲proxy,當child.getParent().getName()或child.getParent().f()時,parent都會被抓取,若設爲no-proxy,調用child.getParent().f()時,parent是不會被抓取的,同時這種方式須要編譯時字節碼加強,不然和proxy沒區別。 (注:測試發現真和proxy同樣,不能理解 編譯時字節碼加強,要再哪修改,或是什麼條件?)

若是設置了 lazy="proxy",就   ,當經過 child 來調用其關聯的 parent, 若是調用 parent 類中定義的任何方法,都會抓取 parent (所謂的抓取是否是就是從數據庫查詢,執行一次 select ?)
若是設置了 lazy="no-proxy" ,只有調用 parent 類中牽涉到類變量的方法,纔會抓取 parent,不然,就像調用 f(), 不會抓取 parent  

."編譯時字節碼加強" 是什麼意思?
"字節碼加強"分編譯期和運行期2種,編譯期是修改java類編譯後的class字節碼文件,在上面附加「加強」操做。(不明白why?)

================

lazy (可選 - 默認爲 proxy): 默認狀況下,單點關聯是通過代理的。lazy="no-proxy"指定此屬性應該在實例變量第一次被訪問時應該延遲抓取(fetche lazily)(須要運行時字節碼的加強)。 lazy="false"指定此關聯老是被預先抓取。注意,若是constrained="false", 不可能使用代理,Hibernate會採起預先抓取!

相關文章
相關標籤/搜索