Chapter 8.1☕ 16 min read

Redis Caching

When your API takes 5 seconds, caching brings it down to 1 millisecond.

01The Concept: In-Memory Caching

The Hyderabad IT Park Cafeteria Buffet Analogy:

Imagine the cafeteria chef in HITEC City. If every employee asks for a fresh plate of Biryani, the chef has to cook it from scratch each time (Database Query — slow). Instead, the chef cooks a massive batch and keeps it in the hot buffet counter (Redis Cache). When an employee asks, the chef serves instantly from the buffet. When the buffet runs empty or gets old, the chef cooks a fresh batch.

In Spring Boot, @Cacheable is the annotation that tells Spring: “Check the buffet first. If the data is there, return it. If not, go to the database, and put it in the buffet for next time.”

02Technical Explanation
  1. Redis: An in-memory data structure store. Spring Boot connects to it instead of using local JVM memory.
  2. @Cacheable: Placed on a method. Spring intercepts the method call, checks Redis using the method parameter as a key, and skips the database if found.
  3. @CacheEvict: Clears the cache when data changes (e.g., when you UPDATE or DELETE a book).
03Full Working Code: Redis Cache Setup

First, add the Redis dependency to pom.xml. (Note: You must run a Redis server locally, e.g., via Docker docker run -p 6379:6379 redis).

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

application.properties

spring.data.redis.host=localhost
spring.data.redis.port=6379

The Service Layer (BookService.java)

package com.devinhyderabad;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class BookService {

// Simulating a slow database call
public Book fetchFromDb(Long id) {
try { Thread.sleep(3000); } catch (InterruptedException e) {} // 3 sec delay
return new Book(id, "Redis Guide", "Deva");
}

// 1. @Cacheable: Checks Redis for key "101". If found, returns immediately.
// If not, runs the method, stores the result in Redis, then returns.
@Cacheable(value = "books", key = "#id")
public Book getBookById(Long id) {
System.out.println("Fetching from DB... (This is slow)");
return fetchFromDb(id);
}

// 2. @CacheEvict: When data updates, delete the old cached value
@CacheEvict(value = "books", key = "#id")
public void updateBook(Long id, Book updatedBook) {
System.out.println("Updating DB and evicting cache for ID: " + id);
}
}
04Code Walkthrough

The code above shows the classic pattern:

  • @Cacheable: The first call to getBookById(1) executes the method (3 sec delay) and stores the result in Redis with key books::1. The second call skips the method entirely and returns instantly from Redis.
  • @CacheEvict: When you call updateBook(1, ...), it removes the stale entry from Redis so the next getBookById(1) call fetches fresh data from the database.
05Why It Matters / Interview Note

Interview Question: “What is a Cache Penetration (Cache Miss) attack, and how do you prevent it?”

Answer: Cache penetration happens when a user repeatedly queries for data that doesn’t exist (e.g., ID -1). Since it’s not in the cache, every request hits the database, crashing it. To prevent this, you can cache null values in Redis for a short time, or use a Bloom Filter to quickly reject requests for IDs that definitely don’t exist.

Enterprise Note: The entity you cache (Book) must implement Serializable or you must configure a JSON serializer (like GenericJackson2JsonRedisSerializer) in a RedisCacheConfiguration bean, otherwise Spring will throw a serialization error.

Key Takeaways

  • ✅ Redis stores frequently accessed data in RAM for millisecond response times
  • ✅ @Cacheable checks the cache first and skips the database if data is found
  • ✅ @CacheEvict removes stale cache entries when data is updated or deleted
  • ✅ Cache penetration attacks can flood the DB; use null caching or Bloom filters
  • ✅ Cached objects must be Serializable or use a JSON Redis serializer