Caching in Hibernate With Redis
Learn more about caching in Hibernate.
Join the DZone community and get the full member experience.Join For Free
Hibernate is an open-source, object/relational mapping framework for the Java programming language. The goal of Hibernate is to help developers spare themselves from many tedious, manual data processing tasks. Hibernate is able to create mappings between Java classes and database tables, as well as data types in Java and SQL.
Any non-trivial application working with large quantities of data must rely on caching and other techniques to become more efficient. Caching is a strategy to improve the performance of an application by using a buffer to store frequently accessed data. By reducing the number of database requests and storing the data closer to the CPU, caching can significantly increase an application's speed.
In this article, we'll investigate how you can perform caching in Hibernate using Redisson, a Java wrapper for accessing the in-memory data structure store Redis.
Hibernate: First-Level Vs. Second-Level Caches
Hibernate uses a multi-level caching scheme. The first level is mandatory and enabled by default, while the second level is optional.
The first-level cache (also known as the L1 cache) is associated with Hibernate's Session object, which represents a connection between a Java application and a SQL database. This means that the first-level cache is only available for as long as the Session exists. Each first-level cache is only accessible by the Session object with which it is associated.
When an entity is queried from the database for the first time, it is stored in the first-level cache associated with that Session. Any later queries to this same entity during the same Session will retrieve the entity from the cache, instead of from the database.
The second-level cache (also known as the L2 cache) is disabled by default but can be enabled by modifying Hibernate's configuration settings. This cache is associated with Hibernate's SessionFactory object and is mainly used to store data that should persist across Sessions. Before looking in the second-level cache, applications will always search the first-level cache for the presence of a given entity.
Hibernate also has a third type of cache: the query cache, which is used to store the results of a particular database query. This is useful when you need to run the same query many times with the same parameters.
There are several different implementations of the second-level cache in Hibernate, including Ehcache and OSCache. In the rest of this article, we'll explore another option for second-level caching in Hibernate: Redisson, which allows using Redis as Hibernate cache.
How to Cache with Hibernate and Redis
Redisson is a Redis client in Java that contains implementations of many Java objects and services, including Hibernate caching. All four Hibernate cache strategies are supported by Redisson:
READ_ONLY: Used only for entities that will not change once inside the cache.
NONSTRICT_READ_WRITE: The cache is updated after a transaction modifies the entity in the database. Not able to guarantee strong consistency but can guarantee eventual consistency.
READ_WRITE: Guarantees strong consistency by using "soft" locks that maintain control of the entity until the transaction is complete.
TRANSACTIONAL: Ensures data integrity by using distributed XA transactions. Updates are guaranteed to be either committed or rolled back to both the database and the cache.
Redisson provides various Hibernate CacheFactories, including those with support for local caching. If you plan to use your Hibernate cache mainly for reading operations or you don't want to make too many network round trips, local caching is a smart solution.
RedissonRegionFactory implements a basic Hibernate cache, while the
RedissonLocalCachedRegionFactory (available in Redisson PRO edition) implements a Hibernate cache with support for local caching.
redisson-hibernate dependency can be easily integrated into your project using Maven or Gradle. For JDK 1.8, the Maven settings are:
<dependency> <groupId>org.redisson</groupId> <!-- for Hibernate v4.x --> <artifactId>redisson-hibernate-4</artifactId> <!-- for Hibernate v5.0.x - v5.1.x --> <artifactId>redisson-hibernate-5</artifactId> <!-- for Hibernate v5.2.x --> <artifactId>redisson-hibernate-52</artifactId> <!-- for Hibernate v5.3.x - v5.4.x --> <artifactId>redisson-hibernate-53</artifactId> <version>3.10.2</version> </dependency>
And the Gradle settings are:
// for Hibernate v4.x compile 'org.redisson:redisson-hibernate-4:3.10.2' // for Hibernate v5.0.x - v5.1.x compile 'org.redisson:redisson-hibernate-5:3.10.2' // for Hibernate v5.2.x compile 'org.redisson:redisson-hibernate-52:3.10.2' // for Hibernate v5.3.x - v5.4.x compile 'org.redisson:redisson-hibernate-53:3.10.2'
To define a
CacheFactory in Redisson, insert the appropriate property into the Hibernate configuration:
<!-- Redisson Region Cache factory --> <property name="hibernate.cache.region.factory_class" value="org.redisson.hibernate.RedissonRegionFactory" /> <!-- or --> <property name="hibernate.cache.region.factory_class" value="org.redisson.hibernate.RedissonLocalCachedRegionFactory" />
You will also need to activate Hibernate's second-level cache and specify the Redisson configuration file:
<!-- 2nd level cache activation --> <property name="hibernate.cache.use_second_level_cache" value="true" /> <property name="hibernate.cache.use_query_cache" value="true" /> <!-- Redisson YAML config (located in filesystem or classpath) --> <property name="hibernate.cache.redisson.config" value="/redisson.yaml" /> <!-- Redisson JSON config (located in filesystem or classpath) --> <property name="hibernate.cache.redisson.config" value="/redisson.json" />
Redisson allows you to change many different important parameters for the Hibernate cache, including:
The maximum size of the cache in Redis
Time to live for each cache entry in Redis
Maximum idle time for each cache entry in Redis
The maximum size of the local cache
Time to live for each local cache entry
Maximum idle time for each local cache entry
Eviction policy for the local cache, once the cache's maximum size is reached (LFU, LRU, SOFT, WEAK, or NONE)
Strategy for synchronizing changes to the local cache across all instances (INVALIDATE, UPDATE, or NONE)
Reconnection strategy for loading missed updates after a connection failure (CLEAR, LOAD, or NONE)
Opinions expressed by DZone contributors are their own.
Creating Scalable OpenAI GPT Applications in Java
The Ultimate API Development Guide: Strategy, Tools, Best Practices
Payments Architecture - An Introduction
Application Architecture Design Principles