1. 程式人生 > >hibernate筆記: 關於懶載入和load()方法

hibernate筆記: 關於懶載入和load()方法

重點牢記

1.Load支援懶載入,get不支援懶載入。

2.lazy的生命週期與session相同,lazy載入必須依賴於session一直開啟。

3.Hibernate lazy屬性,在3.x後是預設開啟的,在以前版本中預設是關閉的。

4.hibernate通過cjlib實現代理。

5.load方法加載出來的是代理物件。

6.可以利用Hibernate.initialize(emp)來初始化代理物件達到命中資料庫

7.代理類在未命中資料庫之前,他只有真實物件的ID屬性,其他資料都是沒有的

Empoyee.hbm.xml的配置

  1. <hibernate-mapping  
  2.  package
    =
    "hiber.domain">  
  3.  <class name="Employee" table="employees"  discriminator-value="0"  >  
  4.   <id name="id">  
  5.    <generator class="increment"/>  
  6.   </id>  
  7.   <property name="name" not-null="true"/>  
  8.   <many-to-one name="department" column="department_id" ></many-to-one
    >   
  9.  </class>  
  10. </hibernate-mapping>  

Department.hbm.xml的配置

  1. <hibernate-mapping  
  2.     package="hiber.domain">  
  3.     <class name="Department" table="departments"  discriminator-value="0" >  
  4.         <id name="id">  
  5.             <generator class="increment"/>  
  6.         </
    id>  
  7.         <property name="name" not-null="true"/>  
  8.     </class>  
  9. </hibernate-mapping>  

測試(一):

  1. public class Many2One {  
  2.     /** 
  3.      * @param args 
  4.      */  
  5.     public static void main(String[] args) {  
  6.         add();  
  7.         Employee employee =query();  
  8.         System.out.println(employee.getDepartment().getName());//(1) 進行訪問  
  9.     }  
  10.     /** 
  11.      * 新增一個Department 和Employee 以及它們之間的關聯 
  12.      */  
  13.     static void add(){  
  14.         Session s =null;  
  15.         Transaction t = null;  
  16.         s=HiberUtil.getSession();  
  17.         t=s.beginTransaction();  
  18.         Department department = new Department();  
  19.         department.setName("人事部");  
  20.         Employee employee = new Employee();  
  21.         employee.setName("steve");  
  22.         employee.setDepartment(department);  
  23.         s.save(department);  
  24.         s.save(employee);  
  25.         t.commit();  
  26.         s.close();  
  27.     }  
  28.     /** 
  29.      * 使用load方法測試 懶載入的相關問題 
  30.      * @return 
  31.      */  
  32.     static Employee query(){  
  33.         Session s =null;  
  34.         Transaction t = null;  
  35.         s=HiberUtil.getSession();  
  36.         t=s.beginTransaction();   
  37.         Employee employee = (Employee)s.load(Employee.class1);          
  38.         t.commit();  
  39.         s.close();  
  40.         return employee;  
  41.     }  
  42. }  

結果: 會報錯

  1. Hibernate: select max(id) from departments  
  2. Hibernate: select max(id) from employees  
  3. Hibernate: insert into departments (name, id) values (?, ?)  
  4. Hibernate: insert into employees (name, department_id, id) values (?, ?, ?)  
  5. Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session  
  6.     at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)  
  7.     at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)  
  8.     at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)  
  9.     at hiber.domain.Employee_ _javassist_0.getDepartment(Employee_ _javassist_0.java)  
  10.     at hiber.sth.Many2One.main(Many2One.java:17)  

結果分析: 

 當使用session中的load方法查詢資料庫中的記錄時,我們返回的是一個代理物件,而不是真正需要的那個物件;例如資料庫中存有個Employee表,我們有cn.binyulan.doman.Employee的領域物件,如果查詢Id值為“200626313”的Employee employee = (Employee)session.load(Employee.class,"200626313"),然後我們列印System.out.println(employee.getClass);得到的結果為cn.binyulan.domain.Employee._$$_jvst793_0,名字很奇怪吧,這個物件是Hibernate幫我們生成的,從名字可以看出它是對Employee類的增強類的物件,其實這就是個代理物件,這個物件裡並沒有我們需要的Employee的資料,所以如果你在session關閉後在使用employee來獲取資訊,如除了獲得ID以外的employee.getName();就會出現如下異常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session,這就說明了employee中沒有我們需要的資料了。

      emp物件現在到底是什麼呢,它其實是一個代理類,這個類具有查詢資料庫的能力,當session沒有關閉的時候如果我們呼叫emp.getName等方法;那麼這個類會去查詢資料庫並返回相應的資料。之後我們關閉session之後再去使用這個類就不會有異常了,可是我們如果呼叫emp.getName()只是為了讓代理類去查資料庫,如果別人看我們的程式碼時候覺得這兩句在邏輯上根本就沒有用,別人就很容易註釋掉,一註釋掉就又會出現異常了,所以hibernate提供了一個方法Hibernate.initialize(emp);這樣就可以初始化這個代理物件了。

       不知道大家注意到沒有,上面的那句程式碼Employee emp = (Employee)session.load(Employee.class,1)把emp強制轉化為Employee型別,有人會問:不是返回的是代理物件麼,那怎麼又強制轉換成Employee了呢,其實代理類是Employee的子類,它具有了比父類更強的能力(資料庫查詢),這個類是怎麼生成的呢?其實hibernate使用了asm.jar和cglig-2.1.3.jar,在記憶體中修改Employee類的位元組碼,修改後的位元組碼只要符合class檔案的規則,就可以創建出代理物件。

       Domain物件不應該final的,大家現在應該明白為什麼了吧,如果是final的,那麼就不可以繼承,當然也就不可以產生代理物件,也就不能實現懶載入了,如果你不用懶載入,那麼把domain物件設計成fianl的也是可以的。