1. 程式人生 > >Hibernate中get()和load()方法的區別

Hibernate中get()和load()方法的區別

在hibernate中我們知道如果要從資料庫中得到一個物件,通常有兩種方式,一種是通過session.get()方法,另一種就是通過session.load()方法,然後其實這兩種方法在獲得一個實體物件時是有區別的,在查詢效能上兩者是不同的。

一.load載入方式

當使用load方法來得到一個物件時,此時hibernate會使用延遲載入的機制來載入這個物件,即:當我們使用session.load()方法來載入一個物件時,此時並不會發出SQL語句,當前得到的這個物件其實是一個代理物件,這個代理物件只儲存了實體物件的id值,只有當我們要使用這個物件,得到其它屬性時,這個時候才會發出SQL語句,從資料庫中去查詢物件。

session = sessionfactory.openSession();

//通過load的方式載入物件時,會使用延遲載入機制,此時並不會發出sql語句,只有當我們需要使用的時候才會從資料庫中去查詢        
Student s = (Student)session.load(Student.class, 2);

我們看到,如果我們僅僅是通過load來載入我們的Student物件,此時控制檯不會從資料庫中查詢出該物件,即並不會發出SQL語句。只有當我們要使用該物件時:

session = sessionfactory.openSession();
    
Student s = (Student)session.load(Student.class, 2);
System.out.println(s);

此時控制檯會發出了SQL查詢語句,會將該物件從資料庫中查詢出來。

其實第一次通過load獲得的物件是一個代理物件,這個代理物件僅僅儲存了id這個屬性:

session = sessionfactory.openSession();
            
//通過load的方式載入物件時,會使用延遲載入機制,此時得到的物件其實是一個代理物件,該代理物件裡面僅僅只有id這個屬性
//而且即使資料庫中沒有Id=10的欄位,也不會報錯
Student s = (Student)session.load(Student.class, 10);
System.out.println(s.getId());

如果我們只打印出這個物件的id值時,此時控制檯會打印出該id值,但是同樣不會發出SQL語句去從資料庫中去查詢,即使資料庫中沒有Id=10的欄位,也不會報錯。這就印證了我們的這個Student物件僅僅是一個儲存了id的代理物件,但如果我需要打印出Student物件的其他屬性值時,這個時候會不會發出SQL語句呢?答案是肯定會發出的。

那第二次執行load是怎麼樣的呢?

session = sessionfactory.openSession();
            
Student s1 = (Student)session.load(Student.class, 2);
System.out.println(s1.getAge());
Student s2 = (Student)session.load(Student.class, 2);
System.out.println(s1==s2);//輸出true

下圖顯示了第一次執行Session的load()方法的過程。load方法先到Session快取中查詢OID為2的Student物件,由於Session快取還不存在,於是load()建立一個OID為2的物件並返回,只有當要用到這個物件的時候,才到資料庫中去查詢,並將其儲存在Session快取中。

下圖顯示了第二次執行Session的load()方法的過程。load()方法先到Session快取中查詢OID為2的Student物件,因為已經存在這樣的Student物件了,就直接返回該Student物件。因此在上面的程式程式碼中,變數s1和變數s2引用的是同一個Student物件。

二.get載入方式

相對於load的延遲載入方式,get就直接的多,當我們使用session.get()方法來得到一個物件時,不管我們使不使用這個物件,此時都會發出SQL語句去從資料庫中查詢出來。

session = sessionfactory.openSession();
            
Student s1 = (Student)session.get(Student.class, 2);
Student s2 = (Student)session.get(Student.class, 2);

System.out.println(s1==s2);

下圖顯示了第一次執行Session的get()方法的過程。get方法先到Session快取中查詢OID為2的Student物件,由於Session快取還不存在,於是到資料庫中去查詢,並將其儲存在Session快取中。

下圖顯示了第二次執行Session的get()方法的過程。get()方法第二次執行的過程與load()方法一致,先到Session快取中查詢OID為2的Student物件,因為已經存在這樣的Student物件了,就直接返回該Student物件。因此在上面的程式程式碼中,變數s1和變數s2引用的也是同一個Student物件。

三.使用get和load時的要注意的地方

1、load()方法的這種載入方式稱為懶載入,我們可以通過修改配置檔案取消懶載入

<class  name="Student" lazy="false" table="student">

2、如果確定資料庫中有這個物件就用load(),不確定就用get()(這樣效率高)

3、如果使用get方式來載入物件,當我們試圖得到一個id不存在的物件時,此時會報NullPointException的異常。

session = sessionfactory.openSession();
            
Student s = (Student)session.get(Student.class, 10);        
System.out.println(s.getName());    

這是因為通過get方式我們會去資料庫中查詢出該物件,但是這個id值不存在,所以此時user物件是null,所以就會報NullPointException的異常了。

4、如果使用load方式來載入物件,當我們試圖得到一個id不存在的物件時,此時會報ObjectNotFoundException異常。

session = sessionfactory.openSession();
            
Student s = (Student)session.load(Student.class, 10);        
System.out.println(s.getName());

這是因為使用load時,此時的Student物件是一個代理物件,僅僅儲存了當前的這個id值,當我們試圖得到該物件的name屬性時,這個屬性其實是不存在的,所以就會報出ObjectNotFoundException這個異常了。