Spring Boot Caching
Caching stores the result of an expensive operation so your app returns it instantly on the next call instead of repeating the work. Spring Boot's caching layer lets you add caching with one annotation — no manual cache management needed.
Why Caching Matters
Without cache: With cache: ────────────────────────────── ────────────────────────────────── Request 1: query DB (50ms) Request 1: query DB (50ms) → store Request 2: query DB (50ms) Request 2: return from cache (1ms) Request 3: query DB (50ms) Request 3: return from cache (1ms) Request 100: query DB (50ms) Request 100: return from cache (1ms) 100 requests = 5000ms total 100 requests ≈ 149ms total
Caching is especially useful for data that changes infrequently — product catalogs, country lists, user profiles.
Enable Caching
@SpringBootApplication
@EnableCaching ← Activates Spring's caching infrastructure
public class DemoApplication { ... }
The Three Core Annotations
Annotation When It Runs What It Does
────────────────── ──────────────────────── ────────────────────────────────
@Cacheable Before method runs Return cached value if it exists;
run method and cache result if not
@CachePut Always runs method Always runs and updates the cache
@CacheEvict Always runs method Removes value(s) from the cache
@Cacheable — The Most Common
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product findById(Long id) {
// This code runs only on the FIRST call for each id
// Subsequent calls return the cached result
return productRepo.findById(id).orElseThrow();
}
}
What happens on each call:
Call 1: findById(5)
→ Cache miss (nothing stored for key "5")
→ Runs method → queries DB → returns Product
→ Stores Product in cache under key "5"
Call 2: findById(5)
→ Cache hit (Product stored under key "5")
→ Returns Product immediately — no DB query
Call 3: findById(7)
→ Cache miss (nothing stored for key "7")
→ Runs method → queries DB → returns Product
→ Stores Product in cache under key "7"
@CachePut — Update the Cache
@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
Product saved = productRepo.save(product);
return saved; ← Cache is updated with the new value
}
@CacheEvict — Remove from Cache
// Remove one entry
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
productRepo.deleteById(id);
}
// Clear the entire cache
@CacheEvict(value = "products", allEntries = true)
public void clearProductCache() { }
Default Cache (ConcurrentHashMap)
Out of the box, Spring uses an in-memory ConcurrentHashMap as the cache store. This works for a single server. For multiple servers, use a distributed cache like Redis.
Using Redis as a Cache
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
# application.properties spring.cache.type=redis spring.data.redis.host=localhost spring.data.redis.port=6379 # Cache entries expire after 10 minutes spring.cache.redis.time-to-live=600000
Caching with Conditions
// Only cache if the result is not null
@Cacheable(value = "products", key = "#id", unless = "#result == null")
public Product findById(Long id) { ... }
// Only cache for active products
@Cacheable(value = "products", key = "#id", condition = "#id > 0")
public Product findById(Long id) { ... }
Cache Flow Diagram
Request: findById(5)
│
▼
Cache: check key "5"
│
├── HIT → return Product immediately (no DB)
│
└── MISS → run method
│
▼
Query Database
│
▼
Store in cache
│
▼
Return Product
Summary
- Enable caching with
@EnableCachingon the main class @Cacheablereturns cached data on repeat calls without hitting the DB@CachePutalways runs the method and refreshes the cache@CacheEvictremoves stale entries when data changes- Use Redis for distributed caching when running multiple server instances
