Step by Step: Spring Boot + JPA + MySQL + Redis as Cache

In this tutorial, we will take a look at how to use Redis Database as a Cache for your Spring Boot Application.

Follow this tutorial for setting up Redis with Spring Boot: Link

In software development, caching really helps to improve the performance of the application and thus reduces the load on resources. In a Java application, caching can be used to store frequently accessed data in memory, thus making decreasing the latency of your application.

Redis is a one of the popular in-memory data store that can be used for caching in Java applications.

For this tutorial, we will use MySQL database as our primary database, we will keep the application simple so that it's easy to understand the concept of caching and the configuration.

Step 1: MySql + Redis configuration


#Redis as Cache

Note: Again! To keep it simple I am using Redis Cloud.

Gradle Configuration

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.0.6'
	id 'io.spring.dependency-management' version '1.1.0'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-redis'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.jetbrains:annotations:23.0.0'
	implementation 'mysql:mysql-connector-java:8.0.14'


tasks.named('test') {

Step 2: Our Entity

Keeping it really simple with an userId and userName fields.

package com.example.redisdemo;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;


public class DbUser implements Serializable {

    private static final long serialVersionUID = 1L;

    public DbUser(int userId, String userName) {
        this.userId = userId;
        this.userName = userName;

    public DbUser() {

    private int userId;

    private String userName;

    public int getUserId() {
        return userId;

    public void setUserId(int userId) {
        this.userId = userId;

    public String getUserName() {
        return userName;

    public void setUserName(String userName) {
        this.userName = userName;


Step 3: Spring JPA Repository class for DbUser

package com.example.redisdemo;

import io.lettuce.core.dynamic.annotation.Param;
import org.springframework.stereotype.Repository;

import java.util.Optional;


public interface DbUserRepository extends JpaRepository<DbUser,Integer> {

    public Optional<DbUser> findUserByUserId(Integer userId);
    public DbUser save(DbUser user);

    @Query("update DbUser u set u.userName = :userName where u.userId = :userId")
    void updateUserName(@Param("userId") Integer userId, @Param("userName") String userName);

    void deleteUserByUserId(Integer userId);

Step 4: User Service class

package com.example.redisdemo;

import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.stereotype.Service;

import java.util.Optional;

@CacheConfig(cacheNames = "dbUsers")
public class UserService {

    DbUserRepository dbUserRepository;

    @Cacheable(key = "#userId",value = "dbUsers")
    public Optional<DbUser> findUserByUserId(Integer userId) {
        System.out.println("User fetched from Db!");
        return dbUserRepository.findUserByUserId(userId);

    public DbUser save(DbUser user) {

    @CacheEvict(key = "#userId", value = "dbUsers")
    public void updateUser(Integer userId, String userName) {

    @CacheEvict(key = "#userId", value = "dbUsers")
    public void deleteUserByUserId(Integer userId) {

Step 5: User Controller

package com.example.redisdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

public class UserController {

    UserService userService;

    FlushRedis flushRedis;

    @GetMapping(path = "/get-user/{userId}")
    public Optional<DbUser> getUserName(@PathVariable("userId") int userId) {
            return userService.findUserByUserId(userId);

    @PostMapping(path = "/add-user")
    public void addUser(@RequestBody DbUser user) {
        System.out.println("User Saved!");;

    @PostMapping(path = "/update-user")
    public void updateUSer(@RequestBody DbUser user) {
        System.out.println("User Saved!");

    @DeleteMapping(path = "/delete-user/{userId}")
    public void deleteUSer(@PathVariable("userId") int userId) {
        System.out.println("User Saved!");


As you may see we have performed all CRUD operations using Spring Data JPA + MySQL, as well as made use of Redis as Cache to be in Sync with our data.

CRUD Operations cURL Commands

  1. Create User:

    curl --location 'http://localhost:8080/add-user' \
    --header 'Content-Type: application/json' \
    --data '{
        "userId": 10,
        "userName": "Harry"
  2. Retrieve User:

    curl --location 'curl --location 'http://localhost:8080/get-user/10' \
    --header 'Content-Type: application/json''
  3. Update User:

    curl --location 'curl --location 'http://localhost:8080/update-user' \
    --header 'Content-Type: application/json' \
    --data '{
  4. Delete User:

    curl --location --request DELETE 'http://localhost:8080/delete-user/10'

You may also use clients like Postman to perform these API calls.

CRUD Operations using Postman for SpringBoot

I have added some SYSOUT logs to the Service layer and set the cache timeout to 5 seconds, when you will try to get the data using the get-user API call, you will see that the first request is from the MySQL Database and subsequent next until 5 seconds are from Redis Cache.

Facing issues? Have Questions? Post them here! I am happy to answer!

Author Info:

Rakesh (He/Him) has over 14+ years of experience in Web and Application development. He is the author of insightful How-To articles for Code2care.

Follow him on: X

You can also reach out to him via e-mail:

Copyright © Code2care 2024 | Privacy Policy | About Us | Contact Us | Sitemap