Hibernate, JPA, Spring DATA JPA, Hibernate Proxy and Architectures

Why should we use ORM Tools?

Berat Yesbek
7 min readJan 29, 2024

Greetings, everyone; today, we will discuss the Hibernate and JPA architecture. I am going to publish a couple of articles about Hibernate. This is the first one. Let’s refresh our coffees and get started! ☕ 📰😊

Before jumping into our article, I want to answer an important question: Why do we need to use ORM Tools such as Hibernate, Eclipse Link, EF core, etc?

This is a really great question, actually. We developers usually have a few months to create a new project or two weeks to add new features to our business logic. When we consider this timeline, writing SQL codes for our business logic will come at a time cost; therefore, the creators of the ORM tool thought that would make CRUD operations easier for the developers.

ORM tools prevent repeat SQL codes and code complexity and provide readability and clarity of the code.

On the other hand, every good thing comes at a cost in our lives. ORM tools are one of them. Unfortunately, we do not realize that we paid the price until we face the result like in life 😉. Obviously, these tools execute many operations under the hood, such as mapping and converting SQL commands. This is the reason most of these ORM tools have worse performance than Native SQL Queries.

In light of these thoughts, it completely depends on the requirements. If you have a large-scale system and complex relations, you should prefer to Native Queries. The basic question here what is your priority? Is it performance or clarity and readability?

Lastly, the cache mechanism is the single biggest reason for choosing Hibernate entity caching, which is what makes a data-centric application high-performance, i.e., keeping the app away from the DB.

What is Hibernate

Hibernate is an ORM (Object Relational Mapping) tool that provides a framework to map OOP domain models to relational database tables in the Spring Boot application.

What is ORM

ORM is a technique that provides interaction with a database using OOP languages. Hereby, it provides simplicity in discrepant database operations like creating, reading, updating and deleting.

What is JPA and Spring Data JPA

JPA is a standard that persists and retrieves information from a non-volatile storage system, mapping Java objects to tables in a database.

  • The entity manager API can persist, update, retrieve or remove objects from a database.
  • The entity manager API can provide ORM without requiring JDBC or SQL code.
  • JPA provides a query language that can retrieve objects without writing massive SQL queries

Spring Data JPA uses JPA to store data in a relational database. Hibernate is a JPA implementation.

Hibernate, Explips Link, or any other JPA provider may be used. Spring Data is not an implementation or JPA provider; it is just an abstraction to reduce the boilerplate code significantly.

JPA is not a framework. It is a standard and concept.

JPA Architecture

Explanation of JPA units

How Persistence Operation works

Hibernate is a JPA provider, while Spring Data JPA is not a JPA provider. It is just an abstraction that can be used with Hibernate, Eclipse Link, etc.

Repository Pattern

Basically, the repository pattern manages fundamental CRUD operations in a BaseRepository class. Let me talk about this in the picture.

The repository pattern involves creating a Generic BaseRepository interface that contains basic CRUD operations for the database. Alongside this interface, there’s a concrete BaseRepositoryImpl class that implements these operations using the EntityManager.

To perform these common operations for entities, we create abstract classes like UserRepository for the User entity. These abstract classes define custom operations relevant to the entity. Additionally, we have concrete classes like UserRepositoryImpl, which extend both the BaseRepositoryImpl and the respective abstract UserRepository.

This approach offers several benefits. Firstly, it encapsulates common database operations within the BaseRepository, promoting code reuse and maintainability. Secondly, by extending abstract classes like UserRepository, we can define entity operations while inheriting the generic CRUD functionality from the base repository. Overall, this structure promotes modularity, abstraction, and efficient management of database interactions within the application.

Let’s see the code in the below: FULL_CODE

Generic BaseRepository

package com.beratyesbek.basicjparepositorypattern.repository.base;

import com.beratyesbek.basicjparepositorypattern.model.BaseEntity;

import java.util.List;

public interface BaseRepository<E extends BaseEntity, I> {
void save(E entity);

void update(E entity, I id);

List<E> findAll();

E findById(I id);
}

Generic BaseRepositoryImpl

package com.beratyesbek.basicjparepositorypattern.repository.base;

import com.beratyesbek.basicjparepositorypattern.model.BaseEntity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


public class BaseRepositoryImpl<E extends BaseEntity, I> implements BaseRepository<E, I> {

@PersistenceContext
private EntityManager entityManager;
private final Class<E> entityClass;

public BaseRepositoryImpl(Class<E> entityClass) {
this.entityClass = entityClass;
}

@Override
@Transactional
public void save(E entity) {
entityManager.persist(entity);
}

@Override
@Transactional
public void update(E entity, I id) {
E result = entityManager.find((Class<E>) entity.getClass(), id);
if (result != null) {
entityManager.merge(result);
}

}

@Override
@Transactional
public List<E> findAll() {
return entityManager.createQuery("SELECT e FROM " + entityClass.getSimpleName() + " e", entityClass).getResultList();
}

@Override
@Transactional
public E findById(I id) {
return entityManager.find(entityClass, id);
}
}

UserRepository for User entity

package com.beratyesbek.basicjparepositorypattern.repository;

import com.beratyesbek.basicjparepositorypattern.model.User;
import com.beratyesbek.basicjparepositorypattern.repository.base.BaseRepository;


public interface UserRepository extends BaseRepository<User, Integer> {
}

UserRepositoryImpl for User Entity

package com.beratyesbek.basicjparepositorypattern.repository;

import com.beratyesbek.basicjparepositorypattern.model.User;
import com.beratyesbek.basicjparepositorypattern.repository.base.BaseRepositoryImpl;
import org.springframework.stereotype.Component;

@Component
public class UserRepositoryImpl extends BaseRepositoryImpl<User, Integer> implements UserRepository{

public UserRepositoryImpl() {
super(User.class);
}
}

JPA Repository Pattern

The JPA repository pattern contains database operations that make it easier for us. At the same time, the JPA repository can work with Hibernate, Eclipse Link, etc. It is just an abstraction.

JPA uses a similar repository pattern under the hood.

As you can see, we have entities, and each entity has its own repositories that have been extended from the JpaRepository interface in the background. The JPA repository works with EntityManager, and It works with Hibernate, which works with JDBC.

Hibernate Architecture

Hibernate has a layered architecture which helps the user perform operations without touching anything under the hood. Hibernate provides ORM for persistence service.

Configuration Object

Usually, the Configuration Object is created once during the application lifecycle; additionally, it is the first hibernate object that is created. It represents the database and other configurations.

SessionFactory Object

SessionFactory object is created using Configuration Object. The SessionFactory object is a heavyweight object. It is usually created when the application is initialized. Additionally, The SessionFactory is a thread-safe object and is used by other threads.

Session Object

The session object is used to provide the database connection. It was designed as a lightweight object that is to be created each time when database interaction is required. In addition, SessionObject is not recommended to be retained for later use because it is not thread-safe.

Transaction Object

The Transaction object is used whenever we want to perform operations on an entity, committing or rolling back changes according to the result.

Query Object

The query object uses SQL or HQL (Hibernate Query Language) to retrieve data from the database. The query instance is obtained by calling the createQuery method that belongs to the Session object.

Criteria Object

It usually uses dynamic queries that are obtained from Session objects.

Hibernate Proxy

Hibernation involves two fetching-type strategies: Lazy and Eager loading.

Think about it: you have users that have thousands of login histories. Obviously, when you want to retrieve the users from the database, massive data will come at a cost because of the associated login history entity. That’s why Hibernate uses Lazy loading as a default strategy, which means retrieving data until it is needed. This will enhance the performance of the application. Hibernate manages this phenomenon with Proxy Entities.

In summary, a Hibernate proxy is a way to avoid retrieving massive amounts of data until it is needed.

Lazy Fetch Type

When business logic loads users from the database, JPA loads its ID name and email. However, Login Histories only load when it is called. The Lazy Fetch type will enhance the application's performance if an entity contains so many relations involving massive data.

Eager Fetch Type

When business logic loads users from the database, JPA loads its ID, name, email, and all associated entities, such as Login History. This will come at a cost in application performance, and It consumes memory resources. Eager loading is very useful for one-to-one entity relations.

As you can see in the picture, Hibernate uses a proxy in the Lazy-Type fetching strategy. On the other hand, It directly retrieves the data from the database in the Eager-Type fetching strategy.

REFERENCES

Proxy 1

Proxy 2

JPA

Hibernate

I want to thank Cem Başar Başkan for his support in preparing this article.

--

--