Hibernate 1# - entity states overview

Hibernate is the most common choice when it comes to the ORM libraries used in Java backend projects. Being an ORM library Hibernate uses entities rather than SQL statements to manage database changes. In this article we will have a look at all the possible states of entities. This knowledge will give you awareness of what actions will Hibernate perform depending on the entity state. Our examples will be based on a simple Spring project.




Manipulating entity states

While using ORM libraries we trigger database changes by manipulating entities states. Entity class represents database table and entity instance represents row inside this table. 
There are two different interfaces which can be used to handle entity state transitions:
  1. EntityManager
  2. Session
Both enable us to manipulate Persistence Context. Persistence Context is responsible for handling entity states. The difference is that EntityManager is the JPA specification implementation while Session is the Hibernate-specific interface. It is important to remember that while using Hibernate in your application, you can still use EntityManager, which in this case will call Hibernate Session methods behind the scenes. It is considered a better practice to use EntityManager which is independent of ORM library that is used in the project. It means that we will be able to switch from Hibernate to another ORM library fairly easy.

In the examples below we use JpaRepository which extends Spting Data CrudRepository to interact with persistence context. Repositories are additional abstractions over EntityManager

Transcient 

New object which is not yet managed by Hibernate is considered as Transcient. Transcient object is not handled by Hibernate, therefore no database operations will be performed with regard to this object. We can say that Transcient object is not associated with Hibernate Persistence Context. To make Hibernate 'recognize' the object we have to save it. Lets have a look at the example below:

We prepare a new Client object that represents a new entity which we want to save into database. After invoking save() method from JpaRepository we receive a persistent object. If save() wouldn't be called, then the new Client object would not be saved into database since it would stay in Transcient state. 

Persistent

Invoking save() method in JpaRepository for a Transcient entity will trigger database insert during flush time. Method save() returns a new entity which is now managed by Hibernate Persistence Contex and represents row that will be saved into database. It means that it is Persistent. Now Hibernate will track all the changes made to this entity and persist them at the Hibernate session flush time. What does it exactly mean? I will show it soon.
Since Persistent entity represents database row, there is also another way to get an entity which is in Persistent state - by loading it from database:


Entity which is loaded using JpaRepository is Persistent. We can now also see, what does it mean that Hibernate tracks changes and persists entity at the session flush time. We have modified the entity (client's name), however we have not called save() method. We do not have to - Hibernate saves all the changes automatically at the flush time because the entity is managed. In this case flush time takes place when we exit method marked with @Transactional annotation, which means that transaction is commited.


Detached

Lets assume, that previously shown saveNewClient(ClientDto) service method has been called by some controller: 


After returning from saveNewClient(ClientDto) method, the returned entity is detached. We can see the detached entity in ClientsController, line 37. Why is entity detached and what does it mean? Detached entity is not associated with Hibernate Persistence Context because the Persistence Context has been closed. The context has been closed after completing saveNewClient(ClientDto) method annotated as @Transactional - persistence context is being closed when the transaction is finished (commited or rollbacked). The Client entity returned from the saveNewClient is no longer handled by Hibernate - it is detached. It means that any changes made on this entity will not be persisted. What is more - any repository method calls with this entity as a parameter will trigger an exception. 

It is possible to reattach a detached entity back into persistence context using session.update(entityName, entity) method or entityManager.merge(entity)method.


Removed

When entity is removed, it means that the associated row will be deleted from the database during the flush time. Below is the example of how to move an entity to a removed state using JpaRepository:


We move an entity to a removed state by calling a clientRepository.delete(managedClient) method.

Summary

We have learned the basic rule of ORM libraries like Hibernate - database changes are performed by entity state transitions. There are 4 entity states defined by JPA specification, which are consistent with Hibernate entity states:
  1. Transcient - not handled by persistence context yet.
  2. Persistend - all changes made on this entity will be saved to database on flush time.
  3. Detached - entity is not connected with persistence context any more. It can be however attached again using special methods. 
  4. Removed - related database row will be deleted on flush time.





Komentarze

Popularne posty z tego bloga

Spring Data 1# - how repositories work under the hood

Data consistency and performance in web applciation