2009-11-29 96 views
7

有沒有辦法使用休眠對象與冬眠持久性映射?我的數據模型包含許多將相同的對象。我想使用Flyweight設計模式並始終引用相同的物理對象,而不是爲每個相同的對象分別創建一個實例。如何在hibernate中實現這一點?休眠和Flyweight

Btw。是否所有的JVM都以這樣的方式優化字符串的使用:當多次使用同一個字符串時,它總是會是相同的物理實例?

回答

3

這取決於。

只讀您可以通過創建自定義的UserType輕鬆實現輕量級模式,該模式將每次從池中而不是新實例返回對象。

對於實體Hibernate默認情況下是理想的,並希望跨事務保持一致,因此不會在Sessions之間共享實體以避免數據的競爭狀態 - 我不認爲這就是您想要的。

但在情況下,(這是完全不建議沒有真正知道你在做什麼)你可以實現Interceptor.getEntity()其意在二級緩存。在這種方法中,你可以返回一個實體(甚至有一些被其他會話共享),你將有效地爲你的實體創建一個flyweight模式。

但我強烈建議不要這爲您的數據的一致性 - 更好的有通過實體引用不是也嘗試和飛重實際的實體實際不變的輕量級值。

+0

用戶類型是映射flyweight實例的常見狀態的好主意。 (Hibernate和JDBC仍然會引發很多實例。周圍有沒有辦法,至少他們將垃圾收集相當迅速。)能使用CompositeUserType代表一個對象在整個共同狀態? – 2009-11-29 12:46:41

+0

是的,一個複合用戶類型可能可以做到這一點,但爲什麼實體首先作爲一個實體呢?從一開始就讓它成爲一個值對象(組件)。 – 2009-11-29 23:06:38

0

如果您的對象通過身份實現相等,Hibernate將只有與該主鍵關聯的單個實例。我不相信它和Flyweight完全一樣,但重點是你不會有許多相同Hibernate對象的實例。

2

是的,你可以用Hibernate實現享元模式。

flyweight模式是最大限度地減少內存使用的方法每個實例。策略是儘可能多地在輕量級實例之間共享狀態。在你的情況下,可共享狀態是除了hibernate對象標識符和一些額外的狀態以外的所有東西來維護對象標識

每個輕量級實例都需要自己的object identity。附加狀態是實現身份以區分具有共同狀態的對象的方式。

public boolean equals(Object obj){ 
    Fly other; [..]//check type 
    //null checks ommitted 
    return other.myState.equals(myState) && other.commonState.equals(commonState); 
} 

如果對象標識在實例之間共享,hibernate會將所有物理實例(引用)解釋爲同一個實例。 Hibernate使用equals方法來檢查對象標識,並且您的平等實現將不得不返回(! a.equals(a) == true),這是非法的。 Equal必須是反身性的。如果你打破這個契約,所有依賴契約的圖書館都將被破壞(收藏,休眠等)。

您不能使用hibernate對象標識符實現均等方法來區分對象。這會使對象標識依賴於持久狀態(持久或瞬態)。

在hibernate中爲共同狀態建模的一種方法是共享狀態對象和flyweight對象之間的一對多關聯。 (也許有人有一個想法如何映射數據,而無需連接兩個表?)

字符串:只有internalized strings將被共享。大多數時候這不是最好的解決方案。它適用於符號(類名稱,方法名稱等)。 內部化的字符串永遠不會被垃圾收集,並且您必須擁有一個String實例,無論如何將被垃圾回收new String("..").intern()。它不會節省分配。只有次要的優點,即基本字符串不會生存在gc代碼中,或者可以在堆棧中分配(啓用和適用熱點中的逃逸分析)。

1

是否所有的JVM都優化了字符串的使用方式,使得當多次使用相同的字符串時,它將始終是相同的物理實例?

我對此非常懷疑。在同一個類文件中,定義如下:

String s1 = "Yes"; 
String s2 = "Yes"; 

您可能會有s1 == s1。

但如果你有這樣的:

String x = loadTextFromFile(); // file contains es 
StringBuilder b = new StringBuilder(); 
s2 = b.append("Y").append(x).toString(); // s2 = "Yes" 

我不認爲運行時要檢查所有加載的字符串比較 他們的返回值建設者。

所以,總是比較對象的equals()。無論如何,這是很好的建議,因爲每一個好的等於始於:

if (this == o) { 
    return true; 
} 
+0

這是不是比較,而是對內存的消耗。正如Thomas Jung所提到的,您可以使用String.intern()方法來獲取底層字符串。試試看! – paweloque 2009-11-29 11:05:41

+0

我想說的是,如果一個字符串值在編譯時不知道,或無法預先計算,對象將是不同的(無==),即使有,巧合的是,相同的值。 – extraneon 2009-11-29 16:45:47