2009-11-29 95 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