Step 5- Caching in hibernate

 

Cache definition-

Cache is a temporary data which is used to speed up the performance.

Types of caching in hibernate-

Caching LevelDefault OnSession-SpecificQuery Results CachedObjects EvictedConcurrent AccessUsageCode Snippets
First-level CacheYesYesNoYesThread-safeStoring and retrieving entities within a single session//Loading an entity from the first-level cache
Session session = sessionFactory.openSession();
Employee employee = session.get(Employee.class, 1);
Second-level CacheNoNoNoConfigurableConfigurabletoring and retrieving entities across multiple sessions//Enabling second-level cache
true

//Configuring second-level cache provider
org.hibernate.cache.ehcache.EhCacheRegionFactory
Query CacheNoNoYesConfigurableConfigurableCaching the results of a query//Enabling query cache
true

//Using query cache
Query query = session.createQuery(“from Employee”);
query.setCacheable(true);
List employees = query.list();

In the table above:

  • Caching Level : The level of caching, whether it’s first-level, second-level, or query cache.
  • Default On : Whether the cache is enabled by default or not.
  • Session-Specific : Whether the cache is specific to a single session or not.
  • Query Results Cached : Whether the cache stores the results of a query or not.
  • Objects Evicted : Whether the cache automatically evicts stale objects or not.
  • Concurrent Access : The level of concurrent access support provided by the cache.
  • Usage : The use case for which the cache is best suited.
  • Code Snippets : Examples of how to use the cache in code.

1-Session Cache/First level cache in hibernate-

  • First level cache is enabled by default.
  • First level cache can’t be disabled.
  • Objects are retrieved from current session.
    Example-
// Open a session
Session session = HibernateUtil.getSessionFactory().openSession();

// Begin a transaction
session.beginTransaction();

// Retrieve a customer object from the database
Customer customer = session.get(Customer.class, 1L);

// Print the customer's name
System.out.println(customer.getName());

// Retrieve the same customer object again
Customer customer2 = session.get(Customer.class, 1L);

// Print the customer's name again
System.out.println(customer2.getName());

// Commit the transaction
session.getTransaction().commit();

// Close the session
session.close();

In the above example, the first call to session.get(Customer.class, 1L) retrieves the customer object from the database and stores it in the first-level cache associated with the current session. The second call to session.get(Customer.class, 1L) retrieves the customer object from the first-level cache instead of hitting the database again.

It’s worth noting that the first-level cache is associated with a session, so if you open a new session, it will not have access to the objects stored in the first-level cache of the previous session.

Also, it’s important to note that hibernate’s first-level cache is enabled by default, so there is no need to do anything extra to enable it.

2- SessionFactory Cache/Second level cache in hibernate-

  • Second level cache is disabled by default.
  • Second level cache is configured to use.
  • Objects can be retrieved from various sessions.
  • Steps to enable Second level cache-(we are choosing “ehCache” vendor, because it is widely used)

    Step1-
     Add cache usage in hbm file, for which you want to use second level cache
    i.e.<hibernate-mapping>
    <class name=”ClassName” table=”tableName”>
    <cache usage=”read-only” />

    i.e.-
    write-only, read-write only, restricted read-write only, read-only is widely used and famous.
    Step2- 
    Add these 3 lines in cfg file,
    i.e.
    <property name=”cache.provider_class”> org.hibernate.cache.EhCacheProvider
    </property><property name=”hibernate.cache.use_second_level_cache”>true</property>

    <property name=”hibernate.cache.region.factory_class”> org.hibernate.cache.ehcache.EhCacheRegionFactory
    </property>
    step3- Add 2 jars for hibernate second level cache. 
    hibernate-ehCache-x.x.x.jar,
    similar to hibernate-core version.
    ehCache-x.x.jar,
    latest version.

Example –

// Configure Hibernate to use second-level cache
Configuration config = new Configuration();
config.configure();
config.addAnnotatedClass(Customer.class);
config.setProperty("hibernate.cache.use_second_level_cache", "true");
config.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
config.setProperty("hibernate.cache.provider_configuration_file_resource_path", "ehcache.xml");

// Create a new session factory
SessionFactory factory = config.buildSessionFactory();

// Open a session
Session session = factory.openSession();

// Begin a transaction
session.beginTransaction();

// Retrieve a customer object from the database
Customer customer = session.get(Customer.class, 1L);

// Print the customer's name
System.out.println(customer.getName());

// Close the first session
session.close();

// Open a new session
Session session2 = factory.openSession();

// Retrieve the same customer object again
Customer customer2 = session2.get(Customer.class, 1L);

// Print the customer's name again
System.out.println(customer2.getName());

// Commit the transaction
session2.getTransaction().commit();

// Close the session
session2.close();

// Shut down the session factory
factory.close();

In the above example, the first call to session.get(Customer.class, 1L) retrieves the customer object from the database and stores it in the second-level cache. The second call to session2.get(Customer.class, 1L) retrieves the customer object from the second-level cache instead of hitting the database again.

It’s worth noting that, in this example, I’ve configured Hibernate to use the EhCache implementation of second-level cache, and I’ve provided a configuration file for EhCache. The location of this file is specified in the hibernate.cache.provider_configuration_file_resource_path property. This file should contain the configuration settings for the cache, such as the maximum size and eviction policy.

Also, it’s important to note that second-level cache is not enabled by default, so you have to configure it to use it.

It’s important to also note that second-level cache is not associated with a session, it’s shared by all sessions of the same session factory, so if you open a new session, it will have access to the objects stored in the second-level cache, even if it’s from a different session.

Extra-Query Level cache in hibernate-

  • Query Cache is used to cache the results of a query. 
  • Stepes to enable query level cache-
    step 1- Only add this line to cfg file.
    i.e.  <property name=”hibernate.cache.use_query_cache”>true</property>

Example –

Transactional
public List<Employee> getEmployeesByDepartment(String department) {
    Session session = sessionFactory.getCurrentSession();
    Query query = session.createQuery("from Employee where department = :department");
    query.setParameter("department", department);
    query.setCacheable(true); // enable caching for this query
    return query.list();
}

In this example, the query to get employees by department is set to be cached. When the same query is executed again, the results will be returned from the cache instead of hitting the database again. This can greatly improve performance for frequently-executed queries.

Note: This is a simple example for demonstration purpose, in real application you might want to use caching strategy, eviction policy and other features provided by the caching provider(ehcache in this case)