Hibernate Caching Internals, Practical Example
Tags: hibernate, java, advanced, cache
Published: 2022-10-13 16:47:41

## Introduction

When any application server starts (ex: Tomcat), it creates what called by Thread Pool, a **Thread Pool** is a group of threads that are created and ready to serve any request comes to any application attached with this application server.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4peaoo9ruqhnz2up8x3l.png)

Image above describes the request life cycle

1. Client send the request to the server (/students/50).

2. Application server pick a thread from thread pool then attach the request processing to it.

3. Thread starts its journey in the back-end service till get the result and come back to the client.

In this way application server mange requests came to them each request is executed in separate thread, and during the execution, the thread is busy and can not process any another request till it finish, and after finish it became available for another one, and so on.

## Return to Hibernate

Hibernate in order to execute queries on database, it has what called SessionFactory, this factory is responsible for creating a session with database so it can deal with it.

Hibernate creates a session per thread, so regarding to what we discussed before, each request can be processed by separate thread and Hibernate creates a session for each thread to communicate with database, with this way Hibernate manage communication with database.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y53uxx7mk4unwmwwxge2.png)

## Hibernate caching

Hibernate provides a way for query result caching to enhance performance of repetitive queries done among database, and it has multiple strategies for this.

**First level cache**

While Hibernate creates a session per thread, it does a caching in this session object, as below image if you tried this scenario.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wtuuxvzr8yqha8c2r1n.png)

The first call will fire a query to the database and Hibernate is smart enough to cache this information with **Session** object by id, and in the subsequent call Hibernate not need to fire another query, it first looks into **Session** object if it has an id like this, if true then retrieve it.

> this what called First Level Caching and this is done by default.

**Second level caching**

As first level cache is done upon Session objects that created by **SessionFactory**, Hibernate also provide a caching mechanism upon **SessionFactory** that all sessions created from that factory, which means that the first request only will be served from database and all other requests for same data will be served from cache until this data updated.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1d42lq0ckvwulfh59sss.png)

> this strategy of caching needs a cache provider like redis or Ehcache or Memcache, you can use whatever you want, but you need to specify that to Hibernate

## Implementation

First of all, second level cache not enabled by default in Hibernate you have to explicitly enable it.
we will use Ehcache as database for caching with Hibernate in this example.

so we need to add this to pom file


`<dependency
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-ehcache</artifactId>
   <version>5.6.5.Final</version>
</dependency>>`

and add these properties to property file

> spring.jpa.properties.hibernate.cache.use_second_level_cache=true
> spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactorye
and entity like below


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8lku1tb434f527zwqab6.png)


> Note: @Cachable is works as meta-data for this entity, but real caching happen with @Cache 

**Cache by query**

Both **first level** and **second level** caching is working only with getting entity by id, but what if you want to form another query and cache it, this can be done through these steps

add this property to enable cache by query

`spring.jpa.properties.hibernate.cache.use_query_cache=true
`

and this to the query or method


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ka3khqawq8aki9eu0oao.png)

But this is working in different way, it's not cache reference to entities, instead it just cache the IDs from query result, so first query will be like below

> Hibernate:
    select
        student0_.id as id1_0_,
        student0_.name as name2_0_ 
    from
        students student0_ 
    where
        student0_.name=? 

Hibernate will cache the IDs of result of this query, and in subsequent requests for same query and same bind parameters it will get the IDs from caching and fire query like below

> Hibernate:
    select
        student0_.id as id1_0_0_,
        student0_.name as name2_0_0_ 
    from
        students student0_ 
    where
        student0_.id=? 

This will help performance off course as ID column always indexed in databases so it will be faster than real query, but in order to get most benefit you can enable second level cache with query cache, so that the IDs cached in query cache layer and the entity cached in second level cache layer and no need to go to database at all.

## Resources

- [Github demo project](https://github.com/SMMohsen/hibernate-caching)

- [Video about hibernate sessions](https://youtu.be/0O46-771TSE)

- [Hibernate second level cache](https://www.baeldung.com/hibernate-second-level-cache)

IF YOU LIKED THE POST,YOU CAN SUPPORT SUCH CONTENT WITH A CUP OF COFFEE, THANKS IN ADVANCE.

<a href="https://www.buymeacoffee.com/samehmuh95" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>