How does Hibernate detect dirty state of an entity object? - java

Is it using some kind of byte codes modification to the original classes?
Or, maybe Hibernate get the dirty state by compare the given object with previously persisted version?
I'm having a problem with hashCode() and equals() methods for complicated objects. I feel it would be very slow to compute hash code if the object has collection members, and cyclic references are also a problem.
If Hibernate won't use hashCode()/equals() to check the dirty state, I guess I should not use equals()/hashCode() for the entity object (not value object), but I'm also afraid if the same operator (==) is not enough.
So, the questions are:
How does Hibernate know if a property of an object is changed?
Do you suggest to override the hashCode()/equals() methods for complicated objects? What if they contains cyclic references?
And, also,
Would hashCode()/equals() with only the id field be enough?

Hibernate uses a strategy called inspection, which is basically this: when an object is loaded from the database a snapshot of it is kept in memory. When the session is flushed Hibernate compares the stored snapshot with the current state. If they differ the object is marked as dirty and a suitable SQL command is enqueued. If the object is still transient then it is always dirty.
Source: book Hibernate in Action (appendix B: ORM implementation strategies)
It's important to notice however that Hibernate's dirty-checking is independent of the methods equals/hascode. Hibernate does not look at these methods at all (except when using java.util.Set's, but this is unrelated to dirty-checking, only to the Collections API) The state snapshot I mentioned earlier is something similar to an array of values. It would be a very bad decision to leave such a core aspect of the framework in the hands of developers (to be honest, developers should not care about dirty-checking). Needless to say that equals/hascode can be implemented in many ways according to your needs. I recommend you to read the cited book, there the author discuss equals/hascode implementation strategies. Very insightful reading.

Hibernate default dirty checking mechanism will match all mapped properties of all currently attached entities against their initial loading-time values.
You can better visualize this process in the following diagram:

Hibernate does a field-by-field checking to determine the dirtiness of an entity.
So hashCode/equals do not come into the picture at all.
Actually, the field-by-field dirty checking done by Hibernate can be quite costly in terms of performance.
So it provides interfaces like Strategy or Interceptor.findDirty() to handle the same.
Following post explains this in greater detail (alongwith some ideas for applications to optimize it fully): http://prismoskills.appspot.com/lessons/Hibernate/Chapter_20_-_Dirty_checking.jsp

Probably worth adding, as this distracted me for a while: if you are using a CustomType on your persistent object, equals is used for the dirty check.
This stack is from setting a breakpoint in the equals method of my custom data type in Hibernate, MyType, then triggering a transaction and seeing the equals being called.
equals:68, MyType (xxxxxx)
isEqual:105, CustomType (org.hibernate.type)
isSame:119, AbstractType (org.hibernate.type)
isDirty:79, AbstractType (org.hibernate.type)
isDirty:249, CustomType (org.hibernate.type)
findDirty:316, TypeHelper (org.hibernate.type)
findDirty:4622, AbstractEntityPersister (org.hibernate.persister.entity)
dirtyCheck:585, DefaultFlushEntityEventListener (org.hibernate.event.internal)
isUpdateNecessary:242, DefaultFlushEntityEventListener (org.hibernate.event.internal)
onFlushEntity:169, DefaultFlushEntityEventListener (org.hibernate.event.internal)
flushEntities:232, AbstractFlushingEventListener (org.hibernate.event.internal)
flushEverythingToExecutions:92, AbstractFlushingEventListener (org.hibernate.event.internal)
onAutoFlush:50, DefaultAutoFlushEventListener (org.hibernate.event.internal)
accept:-1, 765785095 (org.hibernate.internal.SessionImpl$$Lambda$1238)
fireEventOnEachListener:102, EventListenerGroupImpl (org.hibernate.event.service.internal)
autoFlushIfRequired:1327, SessionImpl (org.hibernate.internal)

does the dirty checking also involve any attached AttributeConverters? what if the value in the java object stays the same but the AttributeConverter logic is changed and does lead to different database values.
so read entity with old AttributeConverter config, write entity with new AttributeConverter config.
the java object stays the same for old and new AttributeConverter but the database values changes because of old and new AttributeConverter config.

It is simple-- when you load/get entity object by id and then set its new field values by setter method and close session without calling update() method. then hibernate automatically update the changed value in the table without affecting other fields. and at the same time entity object is in dirty state.

Related

Which list should be used for hibernate?

We recently joined up to an existing project and in several entity classes we have seen the following code example:
#OneToMany(mappedBy = "department")
private List<Employee> employee= new LinkedList<>();
I had a discussion with a developer about using ArrayList instead of LinkedList for hibernate. But the arguments from both sides were not clear enough.
Usually, i use for many purposes an ArrayList. Here is a good comparison
Does hibernate under the hood work better with that?
Is there a reason why linkedList is used?
Or has it simply been used unknowingly in the project?
The actual implementation used when an entity is loaded from the database is not the same as the default value in the class definition. This is why entity properties which are collections must be specified as an interface type.
Hibernate uses its own collection implementations which are enriched with lazy-loading, caching or state change detection semantics. For this reason, persistent collections must be declared as an interface type.
From https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#collections
If your entity is not loaded from the database then you should specify a default implementation that make sense for the use case, but being aware it'll not be the same implementation when the entity is loaded. Generally, this means just using ArrayList in most situations.

Hibernate: Does Hibernate Always Use Object Proxies?

I thought that object proxies are used only when the class has a field of Collection type, and uses Lazy fetching. But some sources seem to suggest that Hibernate 3 uses proxies for all objects regardless of whether the object has field of collection type or not.
Can someone please explain when Hibernate uses object proxies? Is it all the time, or just in some cases?
As per the Hibernate docs :
By default, Hibernate uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.
So if you have a single object marked as an association (one-to-one or many-to-one) then it will be a proxy object until you try to access it, at which point Hibernate will attempt to populate it with values from the database.
AFAIK a collection will be initialized as null until you try to access it, at which point Hibernate will attempt to hydrate it with values.
As you suggest in your comment, yes, your object is entirely dependent on the proxy object to load the values when you request them.
None of this applies of course if you use fetchType.EAGER on the association. If you are new to Hibernate I suggest perusing this guide that I wrote. It covers things like fetch types and config for different types of relationships.

Hibernate, fetch, HQL and hashCode()

I have a HQL query something ala'
SELECT myclass
FROM
MyClass myclass JOIN FETCH
myclass.anotherset sub JOIN FETCH
sub.yetanotherset
...
So, class MyClass has a property "anotherset" , which is a set containing instance of another class, lets call it MyClassTwo. And, class MyClassTwo has a property yetanotherset which is a set of a third type of class (with no further associations on it).
In this scenario, I'm having trouble with the hashCode implementation. Basically, the hashCode implementation of MyClassTwo, uses the "yetanotherset" property, and on the exact line it accesses the yetanothertest property, it fails with a LazyInitializationException.
org.hibernate.LazyInitializationException: illegal access to loading collection
I'm guessing, this is because the data from "yetanotherset" hasn't been fetched yet, but how do I fix this? I don't particularly like the idea of dumbing down the hashCode to ignore the property.
Additional question, does HQL ignore fetch=FetchType.EAGER as defined in XML or annotations, it seems like it does. But I cant verify this anywhere.
Implementing hashCode() using a mutable field is a bad idea: it makes storing the entity in a HashSet and modifying the mutable property impossible.
Implementing it in terms of a collection of other entities is an even worse idea: it forces the loading of the collection to compute the hashCode.
Choose a unique, immutable property (or set of properties) in your entity, and implement hashCode based on that. On last resort, you have the option of using the ID, but if it's autogenerated, you must not put it in a Set before the ID is generated.
This is hibernate's most famous exception and it is exactly as you described it. The session has been disconnected, transaction closed, and you are attempting to access this collection. JOIN FETCH in your HQL should force EAGER loading to occur regardless of whether than annotation is present.
I suspect that your annotations are malformed, you have missing or out of date jars, or some other problem of that type.
Bump your Hibernate logging level up to generate the SQL hibernate.SQL=debug and investigate exactly what SQL is being executed up to where you see this exception. This should indicate to you whether your hibernate configuration is behaving the way you think its configured.
Post more of your code and the logs and someone might be able to help you spot the error.

Recommendation for using equals in Entities and avoiding LazyInitializationExceptions?

In the beginning there is a problem that wants to be solved. In my case i got an LazyInitializationException while using indexof in a Collection to retrieve an Object for manipulation. Here i start to think about using equals in EntityBeans (OR-Mapper at all). I know there are some discussions about overriding equals in association with OR-Mapper as hibernate like
[1] Entities equals(), hashCode() and toString(). How to correctly implement them?
[2] To equals and hashcode or not on entity classes, that is the question.
[3] Overriding equals and hashCode in Java
I currently have some entities which implements the equals but inside the code i could not use equals several times because of the LazyInitializationExceptions. So i had to workaround and use eg. the name property of the object to identify it's equality. From my point of view the whole 'LazyInitializationException-thing' is not really mentioned in this questions.
I'd like to know have you got some good patterns or real live recommendations how to avoid such exception in an equal-Method. Shall i use some helper Methodes to distinguish if a Object of a class is already initialized (4) or should i apdicate the use of equals and use helper classes instead (2)? And what is about catching LazyInitializationExceptions in the equals?
[Edit]: If you put equals in context with the initialization of the Object then it will gain importance. Sometimes it is nessesary to have the Object fully initialized but sometimes you don't want to. Because you just need the Object itself (name, id, ...) not its Collection-Properties. So just for equalization you have to reattach the Object and load the whole bunch you don't realy need? Are there any other solutions for such a problem?
LazyInitializationException and equals(), hashCode() et al have little to do with each other. You can a LazyInitializationException when a lazily loaded entity tried to access a related entity that has not yet been loaded, and and the entity has been disconnected or evicted from the Session.
There are two fixes for this:
eagerly load the entity, and it's related entities, before closing the session.
Use the "open session in view" pattern to keep the session open for the duration of the request.
Both of these approaches are discussed in the link below.
JavaLobby: Hibernate, Understanding Lazy Fetching

JPA/Hibernate entityManager.persist(..) makes the entity's collection to become null even though they are saved

I have a PurchaseEntity that has a Set inside.
After doing entityManager.persist(purchaseEntity), purchaseEntity itself and purchaseItemEntity's are all saved to DB correctly.
But after that entityManager.persist(purchaseEntity) call, purchaseEntity.getItems() returns null.
Is this a normal behaviour of Hibernate provided entityManager.persist()?
Is there a way to keep the collection remain in the containing entity object after it's persisted?
No, that's not a normal behavior. Furthermore, this is most certainly not Hibernate's doing - it has to be something in your code. Can you post your source?

Categories