15/09/2017
Iām by no means an expert in Hibernate, but I do use it almost every day for my own projects, so I do know a thing or two about how it works.
One topic that had me scratching my head for ages was the Hibernate life cycle. What I mean by the life cycle is the way Hibernate interacts with Java objects at certain points in the existence of said Java objects.
Letās start from the beginningā¦
What the heck is a Hibernate Life Cycle?
You see, Hibernate is picky about your Java objects. Hibernate prefers your objects to be in a certain āstateā, known as the persistent state⦠this persistent state is one of four different states that exist inside of the hibernate persistence life cycle.
Once you have a firm grasp of the different states that an object can be in (as it pertains to Hibernate) youāll be well on your way to mastering the Hibernate framework.
So letās get this Hibernate persistence life cycle lesson started shall we?
Transient
A transient object is one that Hibernate has no awareness of whatsoever. Itās the first step on our journey through the life cycle. When you first create a plain old Java object (via the new keyword) this object can be thought of as being in a transient state.
So really, when you think about it, every object youāve ever created (before you started working with Hibernate) could be thought of as being in a transient state. Again, this is the case because the database has absolutely no idea that this object is in existence.
How this āstateā applies to Hibernate is that Hibernate will not be able to track transient objects and store them in the database (or update the database based on their values).
In order for the database to properly keep track of objects, is for them to be in the next state of the Hibernate persistence life cycle.
Persistent
When an object is in a persistent state, Hibernate is totally aware of it and can keep the database synchronized with itās values.
Before we launch into the persistent state, letās talk about how we can go from transient to persistent.
There are two main ways to make the leap from a transient object to a persistent object:
Loading the object from the database via Hibernate APIs
Saving the object to the database via Hibernate APIs
Ways to Save an Object
Hibernate has a few different ways to save an object to the database, but the two main ways are as follows:
session.save()
session.saveOrUpdate()
Invoking either of these Hibernate methods will shift your transient object into the persistent state (so long as the save is successful).
I wonāt go into detail about how to use these methods, as Iāve already done so in this post.
Ways to Load an Object
There are quite a few ways to load an object from a database. Hereās a couple that I use the most:
session.get()
session.createCriteria()
I wonāt go into detail here, as Iāve already covered how to load data from a database using Hibernate.
Why the Persistent State is King
Hibernateās true abilities are shown when working with persistent objects.
When an object is in a persistent state within a transactional context in Hibernate, magical things happen. Namely, Hibernate will be able to synchronize the persistent object(s) when you manually invoke a save or when the transactional context is closed and committed.
To create this ātransactional contextā I simply rely on the Spring framework and its annotation. Youāve seen this used already in a previous post.
But you can certainly create your own transactional context manually if you do not prefer to use the Spring framework. This just means that youāll be writing some boilerplate transaction management code. Iām not an expert in this area at all, so if youāre interested in researching it further, there are many articles that cover transactions with Hibernate on the web.
In any case, the point Iām trying to get at here is that the majority of Hibernateās āpersistenceā functionality occurs with your object is in a persistent state.
This means that if you want to add new data to the database, youāll need to invoke the session.save() or session.saveOrUpdate() methods to take your transient object into a persistent state.
Or this means that if you want to update existing data in the database, youāll first need to load it into an object via the aforementioned session.get() or session.createCriteria() methods.
Only when youāre modifying / updating persistent objects will Hibernate actually synchronize your changes from the Java object to your database.
Detached
Okay, so you know that the persistent state is key, but you can only be in this state while youāre inside of a transactional context.
In the world of Spring, this means that you will only be in a persistent state while inside of your DAOās āsaveā methods. This is the case because Spring wraps a transactional context around each method in your DAO class. This happens because we used the annotation at the class level.
So what happens one the flow of code leaves your DAOās save method? Well, the transactional context is closed (via the Spring code I just talked about) and your object that was previously in the persistent state is now in a detached state.
The detached state is given to an object that was previously āattachedā (persistent) but has now left the scope of the transactional context.
The āside effectā of this state is that if you make any changes to your object, Hibernate wonāt be tracking them and thus wonāt synchronize the changes to the database. Youāll need to invoke a session.saveOrUpdate(), a sesssion.update(), or a session.merge() in order to re-attach it and make it persistent again in a new transactional context.
This is where things can get a bit wonky though.
You see, since your object was previously persistent, Hibernate still holds a record of this object in its memory. So when your (now detached) object is passed into a session.update() method, Hibernate tries to update only the records that have changed since it last āknewā your object.
There are times when Hibernate just doesnāt know how to handle the updates and can do nothing except throw exceptions. Iāve hit this scenario before and itās quite annoying.
Again, Iām not an expert in this field, so if anyone can explain exactly whatās going on in this particular scenario, then by all means leave a comment below.
In any case, the solution is to use the session.merge() method instead. What the merge() does is just overwrite everything (thus essentially ignoring whatās in Hibernateās memory) with the object that youāre passing into the merge() method.
Removed
Finally, the last state in Hibernateās persistence life cycle is the āremovedā state. This happens when you have a persistent object that youāve flagged to be deleted.
To delete a persistent object, you just invoke the session.delete() method and pass in your persistent object.
Note that you cannot properly delete a non-persistent object, so to properly delete an object youāll need to load it using the methods we discussed earlier (going from transient to persistent).
Once youāve deleted an object and moved to the āremovedā state, you should no longer use that particular object for any reason.