spring-cache
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSpring Cache
Spring Cache
Quick Start
快速入门
java
@SpringBootApplication
@EnableCaching
public class Application {}
@Service
public class UserService {
@Cacheable("users")
public User findById(Long id) {
return userRepository.findById(id).orElseThrow();
}
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}yaml
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=1000,expireAfterWrite=10mjava
@SpringBootApplication
@EnableCaching
public class Application {}
@Service
public class UserService {
@Cacheable("users")
public User findById(Long id) {
return userRepository.findById(id).orElseThrow();
}
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}yaml
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=1000,expireAfterWrite=10mCache Annotations
缓存注解
@Cacheable
@Cacheable
java
@Cacheable("products")
public Product findById(Long id) { }
@Cacheable(value = "products", key = "#category + '-' + #status")
public List<Product> findByCategoryAndStatus(String category, String status) { }
@Cacheable(value = "products", condition = "#id > 0")
public Product findByIdConditional(Long id) { }
@Cacheable(value = "products", unless = "#result == null")
public Product findByIdUnlessNull(Long id) { }
@Cacheable(value = "products", sync = true) // One thread populates
public Product findByIdSync(Long id) { }java
@Cacheable("products")
public Product findById(Long id) { }
@Cacheable(value = "products", key = "#category + '-' + #status")
public List<Product> findByCategoryAndStatus(String category, String status) { }
@Cacheable(value = "products", condition = "#id > 0")
public Product findByIdConditional(Long id) { }
@Cacheable(value = "products", unless = "#result == null")
public Product findByIdUnlessNull(Long id) { }
@Cacheable(value = "products", sync = true) // One thread populates
public Product findByIdSync(Long id) { }@CacheEvict
@CacheEvict
java
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) { }
@CacheEvict(value = "products", allEntries = true)
public void clearProductCache() { }
@CacheEvict(value = "products", key = "#id", beforeInvocation = true)
public void deleteProductBeforeInvocation(Long id) { }java
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) { }
@CacheEvict(value = "products", allEntries = true)
public void clearProductCache() { }
@CacheEvict(value = "products", key = "#id", beforeInvocation = true)
public void deleteProductBeforeInvocation(Long id) { }@CachePut
@CachePut
java
@CachePut(value = "products", key = "#product.id")
public Product saveProduct(Product product) {
return productRepository.save(product);
}
@CachePut(value = "products", key = "#result.id")
public Product createProduct(CreateProductRequest request) {
return productRepository.save(new Product(request));
}java
@CachePut(value = "products", key = "#product.id")
public Product saveProduct(Product product) {
return productRepository.save(product);
}
@CachePut(value = "products", key = "#result.id")
public Product createProduct(CreateProductRequest request) {
return productRepository.save(new Product(request));
}@Caching (Multiple Operations)
@Caching (多操作组合)
java
@Caching(
put = {
@CachePut(value = "products", key = "#result.id"),
@CachePut(value = "productsBySku", key = "#result.sku")
},
evict = {
@CacheEvict(value = "productList", allEntries = true)
}
)
public Product createProduct(CreateProductRequest request) { }java
@Caching(
put = {
@CachePut(value = "products", key = "#result.id"),
@CachePut(value = "productsBySku", key = "#result.sku")
},
evict = {
@CacheEvict(value = "productList", allEntries = true)
}
)
public Product createProduct(CreateProductRequest request) { }@CacheConfig (Class-Level)
@CacheConfig (类级别配置)
java
@Service
@CacheConfig(cacheNames = "products", keyGenerator = "customKeyGenerator")
public class ProductService {
@Cacheable // Uses class config
public Product findById(Long id) { }
@Cacheable(cacheNames = "inventory") // Override cache name
public Inventory getInventory(Long productId) { }
}Full Reference: See managers.md for Caffeine, Redis, EhCache configurations.
java
@Service
@CacheConfig(cacheNames = "products", keyGenerator = "customKeyGenerator")
public class ProductService {
@Cacheable // 继承类级别配置
public Product findById(Long id) { }
@Cacheable(cacheNames = "inventory") // 覆盖缓存名称配置
public Inventory getInventory(Long productId) { }
}完整参考:查看 managers.md 了解Caffeine、Redis、EhCache的配置方式。
Quick Cache Manager Setup
缓存管理器快速配置
Caffeine (Single Instance)
Caffeine (单实例场景)
java
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(Duration.ofMinutes(10))
.recordStats());
return manager;
}java
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(Duration.ofMinutes(10))
.recordStats());
return manager;
}Redis (Distributed)
Redis (分布式场景)
java
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeValuesWith(SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}Full Reference: See advanced.md for Multi-Level Caching, Metrics, Synchronization.
java
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeValuesWith(SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}完整参考:查看 advanced.md 了解多级缓存、指标监控、同步机制相关内容。
Best Practices
最佳实践
| Do | Don't |
|---|---|
| Use Caffeine for single-instance | Skip TTL configuration |
| Use Redis for distributed | Cache mutable objects |
| Configure TTL always | Ignore cache eviction |
| Use sync=true for expensive ops | Use high cardinality keys |
| Implement cache metrics | Cache sensitive data unencrypted |
| 推荐做法 | 不推荐做法 |
|---|---|
| 单实例场景使用Caffeine | 跳过TTL配置 |
| 分布式场景使用Redis | 缓存可变对象 |
| 始终配置TTL | 忽略缓存驱逐策略 |
| 高开销操作使用sync=true | 使用高基数缓存键 |
| 实现缓存指标监控 | 未加密缓存敏感数据 |
Production Checklist
生产环境检查清单
- Cache provider configured (Caffeine/Redis)
- TTL configured for every cache
- Cache eviction on write operations
- Metrics configured
- Serialization tested
- Distributed lock for critical ops
- 已配置缓存提供方(Caffeine/Redis)
- 所有缓存都已配置TTL
- 写操作触发缓存驱逐
- 已配置指标监控
- 序列化逻辑已测试
- 关键操作已配置分布式锁
When NOT to Use This Skill
何时不适合使用本技能
- Distributed caching - Use
spring-data-redis - Redis operations - Use skill
redis - Session storage - Use Spring Session
- 分布式缓存 - 使用
spring-data-redis - Redis操作 - 使用skill
redis - 会话存储 - 使用Spring Session
Common Pitfalls
常见陷阱
| Error | Cause | Solution |
|---|---|---|
| Cache not working | Internal call (same bean) | Use self-injection |
| Null pointer | Null values cached | Use |
| Memory leak | TTL not configured | Set expireAfterWrite |
| Serialization error | Non-serializable objects | Implement Serializable |
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 缓存不生效 | 同一Bean内部调用 | 使用自注入 |
| 空指针异常 | 缓存了空值 | 使用 |
| 内存泄漏 | 未配置TTL | 设置expireAfterWrite |
| 序列化错误 | 对象未实现序列化 | 实现Serializable接口 |
Anti-Patterns
反模式
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Caching mutable objects | Stale data | Cache immutable data |
| No TTL configured | Stale cache forever | Set expireAfterWrite |
| @Cacheable on void | No effect | Only cache with return |
| No cache sync | Race conditions | Use sync=true or locks |
| 反模式 | 问题 | 解决方案 |
|---|---|---|
| 缓存可变对象 | 数据过时 | 缓存不可变数据 |
| 未配置TTL | 缓存永久过时 | 设置expireAfterWrite |
| 给void方法加@Cacheable | 无任何效果 | 仅对有返回值的方法使用缓存 |
| 无缓存同步 | 竞态条件 | 使用sync=true或分布式锁 |
Quick Troubleshooting
快速排障
| Problem | Diagnostic | Fix |
|---|---|---|
| Cache not working | Check @EnableCaching | Add annotation |
| Wrong data cached | Check cache key | Define explicit key |
| Cache not evicted | Check key expression | Verify key matches |
| Self-invocation bypass | Same class call | Inject self |
| 问题 | 排查方式 | 修复方案 |
|---|---|---|
| 缓存不生效 | 检查是否添加@EnableCaching | 添加对应注解 |
| 缓存数据错误 | 检查缓存键 | 显式定义缓存键 |
| 缓存未驱逐 | 检查键表达式 | 确认键匹配规则 |
| 自调用绕过缓存 | 同一类内部调用 | 注入自身实例 |
Reference Files
参考文件
| File | Content |
|---|---|
| managers.md | Caffeine, Redis, EhCache, Key Generators |
| advanced.md | Multi-Level, Metrics, Sync, Testing |
| 文件 | 内容 |
|---|---|
| managers.md | Caffeine、Redis、EhCache、键生成器 |
| advanced.md | 多级缓存、指标监控、同步、测试 |