Spring Boot - Caching with Redis
Last Updated :
30 Aug, 2024
Caching is a crucial optimization technique used to enhance the performance and scalability of web applications. It temporarily stores data in cache memory to reduce access time and load on backend systems. Redis (Remote Dictionary Server) is a popular open-source, in-memory data structure store used as a cache, database, and message broker. In this article, we will guide you on how to integrate Redis caching into a Spring Boot application to improve its efficiency and response times.
Spring Boot Caching with Redis
Caching is crucial for building high-performance, scalable applications. It helps store frequently accessed data in the cache, reducing the need to access slower underlying storage systems like a database. Redis is a popular in-memory data structure store used as a cache, database, and message broker. Spring Boot seamlessly integrates with Redis for caching through its Spring Cache abstraction.
Introduction to Caching and Redis
- Caching: Caching involves storing frequently accessed data in memory so that future requests for that data can be served faster, without fetching it from the primary data source (e.g., database, API).
- Redis: Redis (Remote Dictionary Server) is an open-source, in-memory data store that supports various data structures such as strings, hashes, lists, sets, and sorted sets. Redis is highly performant and commonly used for caching due to its low latency and high throughput.
Why Use Redis for Caching in Spring Boot?
- Performance: Redis operates in-memory, providing extremely low latency and high-speed data access.
- Scalability: Redis handles a large number of read/write operations, making it suitable for highly scalable applications.
- Flexibility: It supports various data types and operations, allowing for complex caching scenarios.
- Persistence: Redis can be configured to persist data to disk, providing a balance between speed and durability.
Spring Cache Abstraction
The Spring Framework provides a caching abstraction that allows you to define caching logic without binding the application to a specific caching solution. This abstraction can be easily integrated with various caching providers, including Redis.
The Spring Cache abstraction uses annotations to define cache behavior:
@EnableCaching
: Enables Spring's annotation-driven cache management.@Cacheable
: Indicates that the method's return value should be cached.@CachePut
: Updates the cache without interfering with the method execution.@CacheEvict
: Removes data from the cache.
How Caching Works with Redis in the Spring Boot
- Cacheable: When
@Cacheable
is used, Spring first checks if the value is present in the Redis cache. If present, it returns the cached value without executing the method. If not, it executes the method, caches the result in Redis, and returns the result. - CachePut: When
@CachePut
is used, it updates the cache with new data, regardless of whether the method was executed or not. - CacheEvict: When
@CacheEvict
is used, it removes data from the cache, which is useful for maintaining cache consistency when the underlying data changes.
Implementation of Caching with Redis in a Spring Boot Application
Step 1: Create the Spring Boot Project
Create a new Spring Boot project using IntelliJ IDEA with the following options:
- Name: redis-spring-boot-crud
- Language: Java
- Type: Maven
- Packaging: Jar
Click on the Next button.
Step 2: Add the Dependencies
Add the following dependencies to your Spring Boot project:
- Spring Web
- Lombok
- Spring Boot DevTools
- Spring Data Redis
- Validation
- Spring Data JPA
- MySQL Driver
Click on the create button.
Project Structure
After Project creation done successfully, then the folder structure will look like the below image:
Step 3: Configure the Application Properties
Open the application.properties
file and add the following MySQL and Redis configuration:
spring.application.name=redis-spring-boot-crud
# Redis configuration
spring.data.redis.host=localhost
spring.data.redis.port=6379
# MySQL Database configuration
spring.datasource.url=jdbc:mysql://localhost:3306/redisdb?useSSL=false&serverTimezone=UTC
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=mypassword
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
# Enable SQL logging
spring.jpa.show-sql=true
Step 4: Create the Product Class
Create the Product
class with fields like id
, name
, and description
:
Java
package com.gfg.redisspringbootcrud.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
}
This class represents a product entity with fields for id
, name
, and description
. It uses JPA annotations to map to the database table.
Step 5: Create the ProductRepository Interface
Create the ProductRepository
interface that extends JpaRepository
for CRUD operations:
Java
package com.gfg.redisspringbootcrud.repository;
import com.gfg.redisspringbootcrud.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
This interface extends JpaRepository
to provide CRUD operations for the Product
entity.
Step 6: Create the ProductService Class with Caching
Create the ProductService
class and use the @Cacheable
, @CachePut
, and @CacheEvict
annotations for caching:
Java
package com.gfg.redisspringbootcrud.service;
import com.gfg.redisspringbootcrud.model.Product;
import com.gfg.redisspringbootcrud.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Cacheable(value = "products", key = "#id")
public Optional<Product> getProductById(Long id) {
System.out.println("Fetching product from database...");
return productRepository.findById(id);
}
@CachePut(value = "products", key = "#product.id")
public Product saveProduct(Product product) {
return productRepository.save(product);
}
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
public List<Product> getAllProducts() {
return productRepository.findAll();
}
}
This service class handles CRUD operations and caching with Redis. It uses caching annotations to control caching behavior for fetching, saving, and deleting products.
Step 7: Create the ProductController Class
Create the ProductController
class to expose CRUD endpoints for products:
Java
package com.gfg.redisspringbootcrud.controller;
import com.gfg.redisspringbootcrud.model.Product;
import com.gfg.redisspringbootcrud.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
Optional<Product> product = productService.getProductById(id);
return product.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}
@GetMapping
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productService.saveProduct(product);
}
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody Product product) {
Optional<Product> existingProduct = productService.getProductById(id);
if (existingProduct.isPresent()) {
product.setId(id);
return ResponseEntity.ok(productService.saveProduct(product));
} else {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
Optional<Product> product = productService.getProductById(id);
if (product.isPresent()) {
productService.deleteProduct(id);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.notFound().build();
}
}
}
This controller exposes RESTful endpoints for CRUD operations on Product
entities. It handles HTTP requests and interacts with the ProductService
.
Step 8: Main Class (Enable Caching in Spring Boot)
Add the @EnableCaching
annotation to the main application class to enable caching support:
Java
package com.gfg.redisspringbootcrud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class RedisSpringBootCrudApplication {
public static void main(String[] args) {
SpringApplication.run(RedisSpringBootCrudApplication.class, args);
}
}
This is the main class of the Spring Boot application. The @EnableCaching
annotation activates caching support.
pom.xml file:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gfg</groupId>
<artifactId>redis-spring-boot-crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-spring-boot-crud</name>
<description>redis-spring-boot-crud</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 9: Run the Application
After all the steps, now run the project and it will start at port 8080.
Step 11. Start the Redis Server
If you are not aware of how to install and running the redis server, then you can refer this article link for better understanding. We can start it using the below command.
redis-server
Step 12: Testing the Application
1. Create the Product
POST http://localhost:8080/api/products
Output:
2. Fetch All the Products
GET http://localhost:8080/api/products
Output:
3. Fetch the Product by ID
GET http://localhost:8080/api/products/1
Output:
4. Update a Product
PUT http://localhost:8080/api/products/1
Output:
5. Delete a Product
DELETE http://localhost:8080/api/products
Output:
6. Fetch the Product by ID (Cached)
GET http://localhost:8080/api/products/1
Output:
The first time this request is made, the product is fetched from the database. On subsequent requests, the product is retrieved from the Redis cache.
Step 13: Verify the Redis Cache
We will now verify the redis cache to check the data can be stored into the Redis Server.
This example project demonstrates the basic CRUD application using Spring Boot application with Redis Caching. By implementing the caching, application can handle the repeated read requests efficiently, improving the performance and reducing the database load.
Best Practices for Redis Caching in Spring Boot
- Choose Appropriate Cache Keys: Use unique and meaningful keys to avoid cache collisions and ensure accurate cache retrieval.
- Set Expiry Times: Configure expiration times to prevent stale data and manage memory usage effectively.
- Monitor Cache Performance: Regularly monitor Redis performance and adjust configurations based on usage patterns to maintain optimal performance.
- Evict Cache When Necessary: Use the
@CacheEvict
annotation to clear stale or invalid data from the cache to maintain consistency. - Use an Appropriate Caching Strategy: Choose the right caching strategy (e.g., read-through, write-through, write-behind) based on the specific needs of your application.
Similar Reads
Spring Boot - Caching
Spring Boot is a project that is built on top of the Spring Framework that provides an easier and faster way to set up, configure, and run both simple and web-based applications. It is one of the popular frameworks among developers these days because of its rapid production-ready environment which e
6 min read
Spring Boot - EhCaching
EhCache is an open-source and Java-based cache. It is used to boost performance. Its current version is 3. EhCache provides the implementation of the JSR-107 cache manager. Features of EhCache are given below: It is fast, lightweight, Flexible, and Scalable.It allows us to perform Serializable and O
5 min read
Bootstrapping Hibernate 5 with Spring
Hibernate 5 is a framework used for mapping object-oriented domain models to relational databases for web applications and is provided by the open-source object-relational mapping (ORM) tool. We provide all of the database information in the hibernate.cfg.xml file within the hibernate framework. The
4 min read
Spring Boot - Integration with Kafka
Apache Kafka is a distributed messaging system designed for high-throughput and low-latency message delivery. It is widely used in real-time data pipelines, streaming analytics, and other applications requiring reliable and scalable data processing. Kafkaâs publish-subscribe model allows producers t
6 min read
Spring Boot - Cache Provider
The Spring Framework provides support for transparently adding caching to an application. The Cache provider gives authorization to programmers to configure cache explicitly in an application. It incorporates various cache providers such as EhCache, Redis, Guava, Caffeine, etc. It keeps frequently a
6 min read
Introduction to Spring Boot
Spring is widely used for creating scalable applications. For web applications, Spring provides Spring MVC, a commonly used module for building robust web applications. The major drawback of traditional Spring projects is that configuration can be time-consuming and overwhelming for new developers.
5 min read
Hot Reload with Spring Boot DevTools
Hot reloading allows developers to see changes made to their application in real-time without restarting the server. In Spring Boot, this is achieved through Spring Boot DevTools. This tool significantly enhances development by reducing the time required to see changes in the application.Hot Reload
3 min read
Observability With Spring Boot
Observability with Spring Boot refers to the ability to understand the internal state of the system based on its outputs. It helps in monitoring, tracing, and logging applications to diagnose issues and maintain their health. In a Spring Boot application, observability can be achieved by integrating
7 min read
Spring Boot â Building REST APIs with HATEOAS
In this article, we will explore how to build RESTful APIs using the Spring Boot with HATEOAS (Hypermedia as the Engine of Application State). HATEOAS is the key component of the REST application architecture, where each resource not only provides the data but also includes links to other actions th
5 min read
Disable @Cacheable in Spring Boot
Caching is an essential feature in modern web applications, providing faster access to frequently used data and reducing the load on databases. In Spring Boot, the @Cacheable annotation is commonly used to cache method results. However, there may be scenarios where you need to disable caching for sp
5 min read