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智慧的資料庫優化。