English 中文(简体)
Hibernate and Flyweight
原标题:

Is there a way to use Flyweight objects with the hibernating persistence mapping? My data model contains many objects that will be the same. Instead of having a separate instance for each of those same objects I d like to use the Flyweight Design Pattern and reference always the same physical object. How to achieve this in hibernate?

Btw. do all JVMs optimize the usage of Strings in a way such that when the same string is used several times, it will always be the same physical instance?

最佳回答

It depends.

For readonly values you can easily implement a flyweight pattern by creating a custom UserType which will return objects from a pool instead of new instances every time.

For entities Hibernate is by default sane and wants to be consistent across transactions and thus won t share entities between Sessions to avoid race conditions of your data - and I don t think that is what you want.

But in case it is (and this is totally non-recommended without really knowing what you are doing) you can implement Interceptor.getEntity() which is intended for second level caching. In that method you can return an entity (even some shared by other sessions) and you will effectively have a flyweight pattern for your entities.

BUT I highly recommend against this for the consistency of your data - much better to have actual immutable flyweight values referenced by entities than also try and flyweight the actual entities.

问题回答

Yes, you can implement the Flyweight pattern with Hibernate.

The flyweight pattern is way to minimize memory usage per instance. The strategy is to share as much state between flyweight instances as possible. In your case the shareable state is everything except the hibernate object identifier and some additional state to maintain object identity.

Each flyweight instance needs its own object identity. The additional state is the way to implement identity to distinguish between objects that share common state.

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

If the object identity is shared between instances hibernate would interpret all physical instances (references) as the same instance. Hibernate uses the equals method to check object identity and your equal implementation would have to return (! a.equals(a) == true) which is illegal. Equal has to be reflexive. If you would break this contract all libraries that depend on the contract will be broken (collections, hibernate, etc.).

You cannot implement the equal method using the hibernate object identifier to distinguish between objects. This would make the object identity dependent on the persistence state (persisted or transient).

One way to model the common state in hibernate is a one-to-many association between shared state objects and flyweight objects. (Maybe someone has an idea how to map the data without joining two tables?)

String: Only internalized strings will be shared. This is not the best solution most of the time. It is appropriate for symbols (class name, method name, etc.). The internalized strings will never by garbage collected and you have to have a String instance that will to be garbage collected anyway new String("..").intern(). It will not save allocations. There is only the minor advantage that the base string will not survive a gc generation or could be allocated on the stack (with escape analysis in hot spot enabled and applicable).

do all JVMs optimize the usage of Strings in a way such that when the same string is used several times, it will always be the same physical instance?

I doubt that very much. In the same class file, when definined like:

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

you ll probably have s1 == s1.

But if you have like:

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

I don t think the runtime is going to check and compare all the loaded strings to the return value of them builder.

So, always compare objects with equals(). That s good advice anyway since every good equals starts with:

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

If your objects implement equality by identity, Hibernate will only have the single instance associated with that primary key. I don t believe it s exactly the same idea as Flyweight, but the point is that you won t have many instances of the same Hibernate object.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签