2010-04-07 150 views
4

我有一個服務方法調用DAO,然後從數據庫返回一個對象。該方法從系統的許多部分調用。但是,一種特定的方法是獲取類型爲ObjectClass _ $$ _ javassist_somenumber的返回類型。這是扔掉的東西。我調用與其他地方完全相同的服務方法,那麼爲什麼hibernate會返回代理而不是自然對象呢?爲什麼hibernate返回代理對象?

我知道有辦法暴露「代理」對象,但我不覺得我應該這樣做。

查詢僅僅是

hibernateTemplate.find("from User u where u.username = ?", username) 

我使用Hibernate 3.3 BTW。

回答

9

它是一個代理對象,以支持延遲加載;基本上只要您通過accessor/getter方法引用子對象或查找對象,如果鏈接的實體不在會話緩存中,則代理代碼將切換到數據庫並加載鏈接的對象。它使用javassist來有效地動態生成對象的子分類實現(儘管我認爲它也可以配置爲使用CGLIB)。

如果沒有以這種方式進行代理,那麼實現無縫延遲加載是不可能的。

我記不起頭頂是否使用急切加載,然後是否返回自然對象。我通常不推薦使用急切的加載,尤其是如果你有很多鏈接的子實體,因爲它很快會成爲一個巨大的性能瓶頸,因爲它會把每個鏈接的對象吸入到內存中。

另外,如果你需要在類的類型區分,而不是使用obj.getClass(),使用Hibernate.getClass(obj)它會給你回自然的對象類,無論它是proxed與否:請參閱Hibernate API的Javadoc here

+0

那麼對象是急切加載,因爲我得到一個代理對象這個特別的電話,我想你不能保證該對象會是。有趣的是,當我從方法A調用DAO.getUser(String username)時,我得到User對象,但從方法B調用完全相同的莊園中的方法,我得到代理。 – predhme 2010-04-07 19:10:34

+1

通常,問題是以這種方式返回的代理*未被正確初始化;否則,如果它被正確填充,事情應該已經正常進行。任何人都知道爲什麼find方法可能會返回未初始化的代理? – 2011-07-22 03:15:57

2

如果不是所有成員都解析完成,Hibernate將返回代理,即對象不完整。這通常是提高性能的一個理想功能,並且(我認爲)是hibernate的默認設置。

如果您不需要代理,可以在hbm.xml文件中禁止延遲加載,即使用預先加載。請檢查hibernate文檔中的確切語法。

若要使用代理對象,不要直接訪問成員,而只能通過getter訪問成員,即使在成員函數內也是如此。當你得到它時,Hibernate魔法會填充該成員。這樣你就不必暴露該對象。也不要在可能的代理對象上使用instanceof。但無論如何,這是一種代碼味道。

+2

Instanceof檢查仍然有效,因爲代理仍然是您班級的子類的實例。不起作用的是類對象的等號或身份比較(由getClass()提供)。 – whiskeysierra 2010-04-07 23:28:59

+0

我遇到了這個問題,但發現上面的說法是不正確的,這是我們如何發現問題。我們迭代一個集合並檢查'instanceof'是否失敗的預期對象。我真的不知道java是如何處理這個內部的,但是我們在println中加入了「instanceof x =」+(obj instanceof x)並且它打印爲false。 Hibernate.getClass(obj)很好,但我想深入瞭解對象未完全初始化的原因。 – mikemil 2013-10-10 15:50:53

+0

@whiskeysierra - 抱歉,忘記了包含您的ID以通知上述評論。 – mikemil 2013-10-10 15:58:15

0

在我看來這表達:

hibernateTemplate.find("from User u where u.username = ?", username) 

應該總是返回POJO,而不是一個代理。這是因爲標準HQL /標準返回非代理對象,而是返回原始實體類的對象。這是懶協會取不同:

@Entity 
class X { 
    @ManyToOne(fetch = FetchType.LAZY) 
    private User user; 
} 

獲取X對象從這裏分貝,我們將在X.user字段(代理User實例)一個懶惰的代理。

現在,它發生了from User where [...]你有時有POJO,有時候代理對象。通常這是因爲在某些執行中User對象首先通過關聯從數據庫中獲取(from X where [...]查詢在給定的hibernate會話中首先被調用)。已經(代理)User實例,即使對於像from User where [...]這樣的簡單查詢,hibernate也會重用此實例。

相關問題