2011-11-08 47 views
9

我想了解什麼區別是在返回的對象和行爲的休眠3.6 session.get()session.load()Hibernate 3.6 - session.get()vs session.load()

javadoc

get()方法:

返回與 指定的標識符,或者,如果不存在這樣的持久化實例空給定的實體類的持久化實例。 (如果 的實例已經與會話相關聯,返回 例如該方法不會返回一個未初始化的實例。)

負載():

返回的持久實例給定的實體類與給定的標識符 ,假設實例存在。當訪問非標識符方法時,此方法可能會返回一個按需初始化的代理實例,其中 可能爲 。

我有三個問題:

  1. 的Javadoc沒有說明何時load()可能會返回一個代理 - 有沒有辦法知道它提前?

  2. load()返回一個代理 - 這意味着load()沒有訪問數據庫,我是否正確?那麼如果我提供了load()的數據庫中不存在的標識符呢?現在我將在會話中使用無效ID代理(無需獲得例外)。現在我想讓另一個持久實例指向那個代理 - 它會工作嗎?對於這種情況,我不需要初始化代理,我只需要它的id(即使它是無效的,因爲它不在數據庫中)。所以我想我是問我的描述是否正確,我是否總是需要在load()之後退回isInitialized()返回的對象,以確保它代表一個有效的實體(或至少一個有效的代理),即有效的ID。

  3. 此外,如果load()返回代理會發生什麼 - 因此代理是已與該會話關聯的實例。然後根據get()的描述:「如果實例已經與會話關聯,則返回該實例。」 - get()也會返回代理嗎?由於根據get()的描述:「此方法永遠不會返回未初始化的實例。」

謝謝!

UPDATE

是以下是否正確?(A)我認爲load()get()將首先嚐試檢查會話高速緩存之前去DB - 所以它不會是正確的說,他們中的任何總是命中數據庫,或總是返回一個代理。

(B)的初始化代理是不一樣的原始實例,你可以在這裏閱讀:http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/

回答

17

(1),(3):

是。您是對的。load()get()將首先檢查是否存在具有相同PK的實例在會話中保留。

如果是,則僅從會話中返回該實例。 (這可能是代理還是實際的實體類的實例)

如果沒有,load()將創建並返回一個代理,而get()會打擊DB和返回實際的實體類的實例。

這兩個方法返回的對象將被關聯並保存在會話中。

所以,get()load()回報代理或實際的實體類是否取決​​於您是否使用get()或load(),以獲得在首次當前會話同一PK的實例。

可以證明這種行爲通過執行以下測試:

Session session = HibernateUtil.getSessionFactory().openSession(); 

Item loadItem= (Item) session.load(Item.class, 1); 
System.out.println(loadItem.getClass().getName()); 

Item getItem = (Item) session.get(Item .class, 1); 
System.out.println(getItem .getClass().getName()); 

如果是代理,印刷類的名字不會是相同的實際實體類的名字。只需將執行順序更改爲load()get()以查看效果。

(2):

如果負載()返回一個代理,它不會在load()訪問DB .The代理將只訪問DB如果除PK其映射屬性被訪問,並且沒有實例與會話相關的PK值相同。

代理訪問數據庫後,具有相同PK代理的實例將與該會話相關聯。因此,當您再次從代理獲取另一個屬性或使用get()獲取相同PK的實例時,數據庫將不會被訪問,因爲可以從會話中找到值。

例如:

/**Session starts***/ 
Item item = (Item) session.load(Item.class, new Long(1)); 
item.getId(); //Will not access DB as only the identifier property is access 
item.getDescription(); // access the DB and initialize the proxy . After that , the item proxy is said to be initialized 
item.getPrice(); //will not access DB as the item with the PK 1 can be get from the session 
Item item2 = session.get(Item.class, new Long(1)) //will not access DB as the item with the PK 1 can be get from the session 

如果load()具有無效ID的實例,然後訪問屬性或在此代理調用一個方法(如isInitialized()),ObjectNotFoundException將被拋出。所以如果你能抓到ObjectNotFoundException,這意味着一個代理加載了一個無效的ID。

如果您想確保該ID在運行時期間有效,您應該使用get()並檢查返回的實例是否爲空。當設置外鍵約束時,load()非常有用。見this

+0

1。但是如果我在會話中已經有一個初始化的實例(對於這個ID),它是不是會返回該實例,而不是代理?此外,javadoc說:「這種方法可能會返回一個代理實例」 - 它不會說「這個方法將永遠」。 2.這是一種設計缺陷 - 因爲根據你的說法,當我有一個代理,我想確保它代表一個實際的數據庫中的數據庫(我總是想確保 - 即使我只使用代理指向其他實例) - 然後我不知道我使用的ID是有效的,直到我初始化它,但在這種情況下,爲什麼使用代理? – rapt

+0

3.你的意思是'load()'在'load()'後面會返回一個初始化的代理,或者只是一個初始化的實例?因爲如果它是後者,那麼我們現在在會話中有兩個對象擁有相同的ID(代理和實例)。順便說一句,我知道有可能有兩個代理代表相同的數據庫ID - 你可以在這裏閱讀:http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/在文本「其次,有可能破壞代理「。 - 在我的原始問題更多的更新。 – rapt

+0

是的。你是對的。你的問題幫助我清除了一些關於'get()'和'load()'的誤解。看到我的更新請 –

相關問題