Skip to content

hamzemostafaei/jpa-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hibernate First-Level Cache in Spring Boot

This project demonstrates how Hibernate's first-level cache operates within a Spring Boot application using JPA. It includes two endpoints that highlight the cache's behavior: one where the cache is not utilized due to separate transactions, and another where it is effectively used within a single transaction.

Project Components

  • CustomerEntity: A JPA entity representing the customer table in the database.
  • CustomerRepository: A Spring Data JPA repository extending JpaRepository for CRUD operations on CustomerEntity.
  • CustomerController: A REST controller with two endpoints to showcase first-level cache behavior:
    • /without-first-level-cache: Shows the absence of caching when repository methods run in separate transactions (Sessions).
    • /with-first-level-cache: Demonstrates caching within a single transaction (same session) using @Transactional.

Scenarios

1. Without First-Level Cache (/without-first-level-cache)

This endpoint calls save and findById from CustomerRepository without an explicit @Transactional annotation on the controller method. As a result, each repository method executes in its own transaction, each with a separate persistence context.

Behavior

  • Transaction for save: A new transaction begins, persists the customer entity to the database, and caches it in the persistence context. The transaction then commits and closes, ending the persistence context.
  • Transaction for findById: A new transaction starts with its own persistence context. Since it doesn’t share the previous context, the entity isn’t available in the cache, and a SELECT query fetches it from the database.

Log Evidence

2025-03-19T21:54:51.184+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2025-03-19T21:54:51.184+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(810818063<open>)] for JPA transaction
2025-03-19T21:54:51.184+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@3b283604]
2025-03-19T21:54:51.185+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] org.hibernate.SQL                        : /* insert for dev.hamze.jpa.test.CustomerEntity */insert into customer (date_of_birth,first_name,last_name,id) values (?,?,?,default)
2025-03-19T21:54:51.185+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2025-03-19T21:54:51.186+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(810818063<open>)]
2025-03-19T21:54:51.186+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(810818063<open>)] after transaction
2025-03-19T21:54:51.186+03:30  INFO 1289930 --- [jpa-test] [nio-8080-exec-6] dev.hamze.jpa.test.CustomerController    : Customer saved without first level cache: CustomerEntity(customerId=5, firstName=John, lastName=Doe, dateOfBirth=2025-03-19)
2025-03-19T21:54:51.186+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2025-03-19T21:54:51.186+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(439371427<open>)] for JPA transaction
2025-03-19T21:54:51.186+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@5a909c5d]
2025-03-19T21:54:51.187+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] org.hibernate.SQL                        : select ce1_0.id,ce1_0.date_of_birth,ce1_0.first_name,ce1_0.last_name from customer ce1_0 where ce1_0.id=?
2025-03-19T21:54:51.187+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2025-03-19T21:54:51.187+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(439371427<open>)]
2025-03-19T21:54:51.187+03:30 DEBUG 1289930 --- [jpa-test] [nio-8080-exec-6] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(439371427<open>)] after transaction
2025-03-19T21:54:51.187+03:30  INFO 1289930 --- [jpa-test] [nio-8080-exec-6] dev.hamze.jpa.test.CustomerController    : Customer found without first level cache: Optional[CustomerEntity(customerId=5, firstName=John, lastName=Doe, dateOfBirth=2025-03-19)]
  • Key Observations:
    • Two distinct transactions are created: one for save and one for findById.
    • Each transaction uses a separate EntityManager (persistence context), which closes after the transaction ends.
    • A SELECT query in the findById transaction confirms the entity wasn’t retrieved from the cache.

2. With First-Level Cache (/with-first-level-cache)

This endpoint is annotated with @Transactional, ensuring that save and findById execute within the same transaction and share a single persistence context.

Behavior

  • Single Transaction: Both save and findById run in one transaction, sharing the same persistence context.
  • Cache Utilization: After save persists the entity, it’s cached in the persistence context. The subsequent findById retrieves it from the cache without issuing a SELECT query.

Log Evidence

2025-03-19T21:56:01.566+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [dev.hamze.jpa.test.CustomerController.withFirstLevelCache]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2025-03-19T21:56:01.566+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(2067982765<open>)] for JPA transaction
2025-03-19T21:56:01.566+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@62535865]
2025-03-19T21:56:01.566+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(2067982765<open>)] for JPA transaction
2025-03-19T21:56:01.566+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
2025-03-19T21:56:01.567+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] org.hibernate.SQL                        : /* insert for dev.hamze.jpa.test.CustomerEntity */insert into customer (date_of_birth,first_name,last_name,id) values (?,?,?,default)
2025-03-19T21:56:01.567+03:30  INFO 1289930 --- [jpa-test] [io-8080-exec-10] dev.hamze.jpa.test.CustomerController    : Customer saved with first level cache: CustomerEntity(customerId=6, firstName=John, lastName=Doe, dateOfBirth=2025-03-19)
2025-03-19T21:56:01.567+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(2067982765<open>)] for JPA transaction
2025-03-19T21:56:01.567+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
2025-03-19T21:56:01.568+03:30  INFO 1289930 --- [jpa-test] [io-8080-exec-10] dev.hamze.jpa.test.CustomerController    : Customer found with first level cache: Optional[CustomerEntity(customerId=6, firstName=John, lastName=Doe, dateOfBirth=2025-03-19)]
2025-03-19T21:56:01.568+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2025-03-19T21:56:01.568+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(2067982765<open>)]
2025-03-19T21:56:01.568+03:30 DEBUG 1289930 --- [jpa-test] [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(2067982765<open>)] after transaction

  • Key Observations:
    • One transaction spans the entire method, using a single EntityManager.
    • The "Participating in existing transaction" log indicates save and findById share the same context.
    • No SELECT query is logged for findById, proving the entity was retrieved from the cache.

Conclusion

This project highlights the role of transactional context in Hibernate’s first-level cache:

  • Without @Transactional: Separate transactions create isolated persistence contexts, preventing cache reuse and requiring database queries.
  • With @Transactional: A shared transaction enables the same persistence context, allowing the cache to optimize performance by avoiding redundant queries.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages