Redis Tutorial 0/42 lessons ~6 min read Lesson 33

    Caching with @Cacheable

    @Cacheable moves cache-aside boilerplate into declarative annotations — Spring Cache abstraction backed by RedisCacheManager stores method results keyed by SpEL expression.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    @Cacheable moves cache-aside boilerplate into declarative annotations — Spring Cache abstraction backed by RedisCacheManager stores method results keyed by SpEL expression. Amazon product services cache getProductByAsin behind @Cacheable("products").

    Configure TTL per cache name, disable caching in tests with @Profile, and always plan eviction on @CacheEvict when data mutates. sync=true on @Cacheable prevents stampede on hot keys.

    Declarative cache is not magic — wrong key expression caches collisions; null results need unless="#result == null" handling.

    Understanding the topic

    Key concepts

    • @EnableCaching on configuration class.
    • RedisCacheManager + CacheConfiguration TTL.
    • @Cacheable cacheNames key SpEL.
    • @CacheEvict on updates/deletes.
    • @CachePut force update cache.
    • sync=true — single-flight on miss.
    text
    flowchart LR
    App -->|GET key| Redis
    Redis -->|miss| DB
    DB -->|populate| Redis
    Redis --> App

    Step-by-step explanation

    1. AOP interceptor wraps @Cacheable method.
    2. Compute cache key from name + SpEL.
    3. Redis GET — hit returns without method call.
    4. Miss executes method; SET result with TTL.
    5. Evict removes key on mutation.

    Syntax reference

    Common commands

    • unless skips caching null.
    • sync=true expensive but stops stampede.
    • Custom RedisCacheConfiguration per cache name TTL.
    bash
    @Cacheable(cacheNames = "products", key = "#sku", unless = "#result == null")
    public Product findBySku(String sku) { ... }
    @CacheEvict(cacheNames = "products", key = "#sku")
    public void updateProduct(String sku, Product p) { ... }

    Informative example

    Product service with cache and eviction — Spring Boot 3:

    java
    @Service
    public class ProductService {
    @Cacheable(cacheNames = "catalog", key = "#sku", sync = true)
    public Product getBySku(String sku) {
    return repository.findBySku(sku).orElseThrow();
    }
    @CacheEvict(cacheNames = "catalog", key = "#sku")
    public void invalidate(String sku) {
    repository.save(/* updated */);
    }
    }

    Register RedisCacheManager bean with Duration.ofMinutes(30) for catalog cache. Enable caching in @Configuration.

    Real-world use

    Real-world use cases

    • Read-heavy repository methods.
    • Expensive aggregation computed once per TTL.
    • Reference data (countries, tax rates).
    • GraphQL DataLoader backend cache.
    • API gateway response cache layer.

    Best practices

    • TTL per cache volatility.
    • Evict on every write path.
    • sync=true on viral hot keys only.
    • Integration test with @CacheEvict clear.
    • Monitor hit rate via custom metrics.
    • Document SpEL key scheme.

    Common mistakes

    • Cache without eviction — stale forever until TTL.
    • Caching entities with lazy JPA collections — serialization pain.
    • Same cache name different key shapes.
    • Caching mutable objects returned by reference.

    Advanced interview questions

    Q1Beginner@Cacheable behavior?
    Check cache first; on miss run method and store result.
    Q2Beginner@CacheEvict when?
    On update/delete so cache stays consistent.
    Q3Intermediatesync=true purpose?
    Only one thread loads cache on miss — stampede protection.
    Q4IntermediateCache null results?
    Use unless SpEL or disable — null caching can hide errors.
    Q5Advanced@Cacheable vs manual RedisTemplate?
    Declarative for simple read-mostly; manual for complex conditional TTL and pipelines.

    Summary

    @Cacheable = declarative cache-aside.

    Ready to mark this lesson complete?Track your journey across the entire course.