We will see Spring Boot Redis Cache example using Redis, Spring Data JPA, Spring Boot, and Oracle/PostgreSQL/MySql database. There is a separate tutorial related to Spring Data Redis where we will use Redis as a database.
In this tutorial, we are going to use Oracle as Database and Redis as a second-level cache. We will see how to implement a second-level cache using Redis to reduce the number of queries in the database to performance improvement. You can check the first level cache tutorial here.
Note – In this example, we are going to use Redis as in In-Memory Datastore. Also application.properties files have been provided for MySQL and PostgreSQL too if you are using a different database than Oracle.
We have the below endpoints to test our example.
Request method | APIs/EndPoints |
POST | http://localhost:9091/student/create |
PUT | http://localhost:9091/student/update |
GET | http://localhost:9091/student/{id} |
DELETE | http://localhost:9091/student/delete |
Installing Redis Server on windows.
Download redis from here for windows and extract somewhere in your local machine.
After download i have change the name of directory to redis-server. Start the redis on clicking redis-server file.
Redis should up and running on port 6379.
Spring Boot Redis Cache Configuration.
Maven changes – we need to add below dependency in pom.xml in order to use redis.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.properties – For oracle database.
# Connection url for the database
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.username=SYSTEM
spring.datasource.password=oracle
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
# Show or not log for each sql query
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto =create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Oracle10gDialect
server.port = 9091
#Redis cache configuration
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
spring.cache.cache-names=student
spring.cache.redis.time-to-live=60000
spring.cache.type=redis – Using this properties we are specifying cache providers. By default, auto-detected according to the environment.
spring.cache.redis.time-to-live=60000 – Time after that entry will get expired. By default the entries never expires.
Check more spring redis cache properties here.
Maven dependency for MySQL and PostgreSQL.
For MySQL.
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
For PostgreSQL.
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
Configuration file for MySQL Database.
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/springbootcrudexample
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
server.port = 9091
#Redis cache configuration
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
spring.cache.cache-names=student
spring.cache.redis.time-to-live=60000
Configuration file for PostgreSQL Database.
application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
server.port = 9091
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
#Redis cache configuration
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
spring.cache.cache-names=student
spring.cache.redis.time-to-live=60000
Spring Boot Second-level cache example using Redis.
Let’s see spring boot redis chache example from scratch.
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springboothazelcast</groupId>
<artifactId>springboothazelcast</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboothazelcast</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
</dependencies>
</project>
Directory structure of application.
Define entity Student.java
package com.javatute.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "student_name")
private String studentName;
@Column(name = "roll_number")
private String rollNumber;
@Column(name = "university")
private String university;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getRollNumber() {
return rollNumber;
}
public void setRollNumber(String rollNumber) {
this.rollNumber = rollNumber;
}
public String getUniversity() {
return university;
}
public void setUniversity(String university) {
this.university = university;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
Note – Our entity must implement Serializable interface in order to use redis othere we will get below exception.
“Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer;
StudentService.java
package com.javatute.service;
import org.springframework.stereotype.Component;
import com.javatute.entity.Student;
@Component
public interface StudentService {
public Student save(Student student);
public Student update(Student student);
public Student get(int id);
public void delete(Student student);
}
Note – See here more about @Component, @Controller, @Service and @Repository annotations here.
StudentRepository.java
Define StudentRepository interface by extending CrudRepository interface. See more details about CrudRepository here.
package com.javatute.repository;
import java.io.Serializable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.javatute.entity.Student;
@Repository
public interface StudentRepository extends CrudRepository<Student,Serializable> {
}
StudentServiceImpl.java
package com.javatute.serviceimpl;
import java.util.Optional;
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 org.springframework.transaction.annotation.Transactional;
import com.javatute.entity.Student;
import com.javatute.repository.StudentRepository;
import com.javatute.service.StudentService;
@Service("bookServiceImpl")
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentRepository studentRepository;
@Transactional
@CachePut(value = "student", key = "#student.id")
public Student save(Student student) {
Student createResponse = studentRepository.save(student);
return createResponse;
}
@Transactional
@Cacheable(value = "student", key = "#id")
public Student get(int id) {
Student student = null;
Optional<Student> studentResponse = studentRepository.findById(id);
if (studentResponse.isPresent()) {
student = studentResponse.get();
} else {
throw new RuntimeException("Record not found");
}
return student;
}
@Transactional
@CachePut(value = "student", key = "#student.id")
public Student update(Student student) {
Student updateResponse = studentRepository.save(student);
return updateResponse;
}
@Transactional
@CacheEvict(value = "student", key = "#student.id")
public void delete(Student student) {
studentRepository.delete(student);
}
}
@CachePut – This annotation is use to update the cache.
@Cacheable – This annotation indicates that the result of calling a method can be cached.
@CacheEvict – This annotation is use to remove the data from cache.
@Transaction – Check a separate tutorial here.
StudentController.java
package com.javatute.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.javatute.entity.Student;
import com.javatute.service.StudentService;
@RestController
@RequestMapping(value = "/student")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping("/create")
public Student createStudent(@RequestBody Student student) {
Student createResponse = studentService.save(student);
return createResponse;
}
@PutMapping("/update")
public Student updateStudent(@RequestBody Student student) {
Student updateResponse = studentService.update(student);
return updateResponse;
}
@GetMapping("/{id}")
public Student getStudent(@PathVariable int id) {
Student getReponse = studentService.get(id);
return getReponse;
}
@DeleteMapping("/delete")
public String deleteStudent(@RequestBody Student student) {
studentService.delete(student);
return "Record deleted succesfully";
}
}
@RestController – This annotation is a combined form of @Controller and @ResponseBody. See more detail here.
Check more about @RequestMapping and @PatVarible.
JpaConfig.java
package com.javatute.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@Configuration
@EnableJpaRepositories(basePackages = "com.javatute.repository")
@EnableCaching
public class JpaConfig {
}
@Configuration – This annotation is used for configuration purpose. See more details about @Configuration annotation here.
@EnableCaching – This is the core Spring annotation that triggers a post-processor that checks all Spring bean for the presence of caching annotations(@Cacheable, @CachePut, and @CacheEvict) and once these annotation detected, creates a proxy that intercepts the method call and handles the caching behavior. The post-processor use to handle the @Cacheable, @CachePut, and @CacheEvict annotations. The @EnableCaching annotation is introduced in Spring 3.1 and available in org.springframework.cache.annotation package. This annotation is used with the class.
application.properties – Defined in beginning.
Let’s run the application.
Spring Boot Redis Cache example testing using postman.
Perform save operation first using below REST API.
POSt – http://localhost:9091/student/create
{
"studentName": "kim",
"rollNumber": "0126CS01",
"university": "rgtu"
}
This will create a student entry in the oracle database and also it will store this entry in the Redis cache for the given time. For example in our case, it will store the data for 60 seconds. We can verify the key using the Redis client.
Double click on redis-cli to start redis client.
Type keys *
Perform retrieve operation first using below REST API.
GET – http://localhost:9091/student/{id}
Let’s verify the log select query should not execute if we retrieve data within 60 seconds. If we perform get operation after 60 seconds it will hit the oracle database and again data will be stored in the Redis cache for the next 60 secs.
Perform update operation using below REST API.
PUT – http://localhost:9091/student/update
{
"id": 1,
"studentName": "jon",
"rollNumber": "0126CS01",
"university": "rgtu"
}
We are going to update studentName field. Once we perform update operation, it will update oracle db as well Redis cache.
Perform update operation first using below REST API.
DELETE- http://localhost:9091/student/delete
This will delete records from Redis cache as well as the oracle database.
Note – Consider we have configured Redis cache for 5 minutes. When we create a new student with id 1, it will store this student into the oracle database as well as into Redis cache and if someone tries to get this student(i.e having id 1) within 5 minutes it will not hit the oracle database, it will get that student from Redis. Suppose someone try to get the same student after 5 minute, this time it will get data from oracle database and also it will store data into Redis.
If some try to update this student using http://localhost:9091/student/update endpoint, it will update the oracle database as well Redis cache. The same applies to the delete operations.
That’s all about Spring Boot Redis Cache Example.
Check other second level cache tutorial from scratch – Step by step guide.
Spring boot second level cache example using Hazelcast
Spring boot second level cache example using ehcache.
You may like.
- Spring Data JPA Query Methods.
- Spring Data JPA greater than Example.
- Spring Data JPA less than Example.
- Spring Data JPA IsNull Example Using Spring Boot.
- Spring Data findById() Vs getOne()
- Spring Data JPA CrudRepository findById()
- Spring Data JPA JpaRepository getOne()
- Spring Data CrudRepository saveAll() and findAll().
- Spring Data CrudRepository existsById()
- Spring Data JPA delete() vs deleteInBatch()
- Spring Data JPA deleteAll() Vs deleteAllInBatch()
- Spring Data JPA JpaRepository deleteAllInBatch()
- Spring Data JPA deleteInBatch() Example
- Spring Data JPA JpaRepository saveAndFlush() Example
- Spring Data JPA CrudRepository count() Example
- Spring Data JPA CrudRepository delete() and deleteAll()
- Spring Data JPA CrudRepository deleteById() Example
- CrudRepository findAllById() Example Using Spring Boot.
Other Spring Data JPA and Hibernate tutorials.
- @Version Annotation Example In Hibernate.
- Session and Session factory in hibernate.
- Hibernate Validator Constraints Example Using Spring Boot.
- @Temporal Annotation Example In Hibernate/Jpa Using Spring Boot.
- Hibernate Table Per Concrete Class Spring Boot.
- Hibernate Table Per Subclass Inheritance Spring Boot.
- Hibernate Single Table Inheritance using Spring Boot.
- One To One Mapping Annotation Example in Hibernate/JPA using Spring Boot and Oracle.
- One To One Bidirectional Mapping Example In Hibernate/JPA Using Spring Boot and Oracle.
- One To Many Mapping Annotation Example In Hibernate/JPA Using Spring Boot And Oracle.
- Many To One Unidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.
- One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.
- Many To Many Mapping Annotation Example In Hibernate/JPA Using Spring Boot.
Download the source code from github.
Spring boot redis cache docs.
Summary – We have seen Spring Boot Redis Cache Example using Oracle database. We covered how to perform CRUD operation using Spring boot Redis cache. We see the configuration file for MySQL and PostgreSQL databases.