1. 程式人生 > >Hibernate 半深入懶載入與懶載入代理類

Hibernate 半深入懶載入與懶載入代理類

標籤(空格分隔): 後端技術學習

前言

在hibernate的使用中,為了減少對資料庫的訪問,對於存在關聯關係對映表使用的時候,我們可以使用懶載入的方式,讓hibernate幫我查詢單個物件資訊的同時,暫緩查詢它所關聯的另一些物件的資訊,當我們真正的使用它所管理的物件的時候後再幫我們查詢關聯物件。同時懶載入的方式也是hibernate為我們預設選擇的方式。雖然懶載入為我們帶來了減少資料庫查詢的好處,但是在使用的過程中如果是對hibernate理解不夠容易出現難以尋找的問題。

引入

在課堂上老師引導我們,瞭解hibernate的查詢方式的時候,介紹了使用懶載入的時候session.load()查詢會返回的內容並不是我們真正的POJO實體物件,實際上返回的是實體物件的代理類。它跟能夠在我呼叫POJO的getXX()方法的時候使用代理的方式幫我們進行資料庫的查詢實現懶載入,然後返回我們需要查尋得關聯物件。接下來我們細細理解一下半深入懶載入與懶載入代理類。

session.load()講解

API指出 session.load()查詢總是返回一個並非直接對應資料庫行的假物件(代理類)。查出來的假物件它所有的屬性也沒有被正式的初始化。對它所有的操作,直到事務提交時才進行對它之前所有操作的合併,然後執行資料庫語句。
同時在事務提交的時候,如果資料庫中原本並沒有假物件對應的行則會丟擲ObjectNotFoundException
如果是沒有使用事務load()查詢,則在進行session.save(“假物件”),session.saveOrUpdate(“假物件”)的時候則會提示org.hibernate.PersistentObjectException: uninitialized proxy passed to save()

的異常。原因仍然假物件(代理類)懶載入。

例如 session.load()

coderInput

Stock stock = (Stock)session.load(Stock.class, new Integer(2));
           StockTransaction stockTransactions = new StockTransaction();
           //set stockTransactions detail
           stockTransactions.setStock(stock);
           session.save(stockTransactions);

Output

Hibernate:
insert into mkyong.stock_transaction (...)
values (?, ?, ?, ?, ?, ?)

注意:實際上並不是 session.load()的所有查詢都返回的是POJO實體物件的代理類,只有在POJO物件的對映檔案*.hbm.xml中指定了懶載入(即沒有設定lazy="false")的時候才會返回POJO實體物件的代理類。否則不是代理類。

session.get講解

相對於session.load(),session.get()就非常直接,使用它的每一次查詢操作返回的都是對應著資料庫中的真實物件,這個物件代表的是資料庫中真實的一行,也不是代理類。
真是因為這個原因session.get()的查詢它是不支援懶載入的。如果查詢的類有關聯物件,它會同時將關聯物件統統查出來。
如果在資料庫的查詢中找不到對應搜尋條件的行則返回null,通過由於在session.get()返回的不是代理類,在session.close()後它不會被銷燬,不會為空。

例如 session.get()

codeInput

Stock stock = (Stock)session.get(Stock.class, new Integer(2));
           StockTransaction stockTransactions = new StockTransaction();
           //set stockTransactions detail
           stockTransactions.setStock(stock);
           session.save(stockTransactions);

Output

Hibernate:
select ... from mkyong.stock stock0_
where stock0_.STOCK_ID=?
Hibernate:
insert into mkyong.stock_transaction (...)
values (?, ?, ?, ?, ?, ?)

代理類

代理類是通過動態代理的方式建立,是由Hibernate框架幫我們建立的,這也是Hibernate框架的面相切面的特點。Hibernate在通過*.hbm.xml檔案幫我們讓資料庫和正真實體之間建立聯絡,同時又為我們提供了關聯關係對映的功能。在使用懶載入模式下的時候使用session.load等查詢的時候,會返回給我們一個代理類。代理類的所有屬性都會在真正使用的時候才會去載入。如果僅僅只是執行了查詢語句,沒有任何的修改訪問操作,實際上最後的事務提交時Hibernate是沒有進行資料庫查詢的。
同時非常重要的一點是Hibernate的會在代理類相關聯session關閉的時候,會同時銷燬代理類。也就是說如果你所使用的引用是代理類,你執行了session.close(),你再去訪問這個代理類就會的到這樣的org.hibernate.LazyInitializationException: could not initialize proxy - no Session報錯提示。
但是如果是使用的session.get(),或者是關閉了懶載入則不會使用到代理類,不會出現上述問題。同時也享受不到Hibernate智慧的資料庫優化。