Spring Boot cookbook · Beginner
Cache service results in Redis with @Cacheable
Speed up slow product lookups with a shared Redis cache and per-cache TTLs.
Approach
Enable caching, configure Redis cache TTLs per cache name with JSON serialization, annotate read methods with @Cacheable and writes with @CacheEvict/@CachePut. Cache immutable DTOs (records), not JPA entities.
Solution
@Configuration
@EnableCaching
class CachingConfig {
@Bean
RedisCacheManagerBuilderCustomizer cacheTtls() {
var json = RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json());
var base = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(json).disableCachingNullValues();
return builder -> builder
.cacheDefaults(base.entryTtl(Duration.ofMinutes(5)))
.withCacheConfiguration("product", base.entryTtl(Duration.ofMinutes(30)))
.withCacheConfiguration("exchange-rates", base.entryTtl(Duration.ofSeconds(60)));
}
}
@Service
class ProductService {
@Cacheable(cacheNames = "product", key = "#id")
public ProductResponse get(long id) {
return repo.findById(id).map(ProductResponse::from).orElseThrow(() -> new NotFoundException("Product " + id));
}
@CacheEvict(cacheNames = "product", key = "#id")
@Transactional
public void rename(long id, String name) {
repo.findById(id).orElseThrow().rename(name);
}
}
Pitfalls
- Calling the cached method from within the same class (proxy bypass).
- Caching entities with lazy relations.
- Evicting before the transaction commits (another request can re-cache stale data) — evict after commit for strictness.
Variations
- Caffeine for local, ultra-fast caches.
@Cacheable(sync = true)to avoid stampedes on a single instance.
Further reading: Spring Boot: Caching
Reference: https://docs.spring.io/spring-boot/reference/io/caching.html
More Spring Boot recipes
- Add correlation IDs to Spring Boot logs
- Add retries and a circuit breaker with Resilience4j
- Authenticate machine clients with API keys in Spring Security
- Consume Kafka messages with retries and a dead-letter topic
- Handle concurrent updates with optimistic locking
- Implement soft delete with Hibernate
- Make POST endpoints idempotent in Spring Boot
- Map entities to DTOs with MapStruct