原来 Spring Cache 还能这么用?这些骚操作让你的开发效率翻倍!
Spring Cache 不仅仅是个简单的缓存注解工具,掌握这些隐藏技巧,能让你的代码性能飙升,代码量减少50%!
一、基础用法:三剑客闯江湖
@Service
public class ProductService {
// 1. @Cacheable:优先读缓存,无缓存时执行方法并缓存结果
@Cacheable(value = "products", key = "#id", unless = "#result.price > 1000")
public Product getProductById(Long id) {
// 模拟数据库查询
return productRepository.findById(id);
}
// 2. @CachePut:更新缓存(始终执行方法)
@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
return productRepository.save(product);
}
// 3. @CacheEvict:删除缓存
@CacheEvict(value = "products", key = "#id", allEntries = false)
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
}
核心参数解析:
|
参数 |
作用 |
应用场景 |
|
value |
指定缓存名称 |
多业务隔离(如:users, products) |
|
key |
自定义缓存键(SpEL表达式) |
细粒度控制(如:#user.id) |
|
unless |
条件阻止缓存(SpEL表达式) |
过滤特定数据(如:价格>1000不缓存) |
|
allEntries |
是否清空整个缓存区域 |
批量删除(如:重置整个分类) |
二、进阶骚操作:让缓存飞起来
1. 多级缓存策略(本地缓存+Redis)
# application.yml
spring:
cache:
type: composite
caffeinespec: maximumSize=500,expireAfterWrite=10s
redis:
time-to-live: 30m
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
return new CompositeCacheManager(
new CaffeineCacheManager("local_cache"),
RedisCacheManager.create(factory)
);
}
}
2. 防止缓存击穿(同步加载)
@Cacheable(value = "products", key = "#id", sync = true)
public Product getProductWithSync(Long id) {
// 高并发时只有一个线程执行加载
return heavyQueryFromDB(id);
}
3. 动态TTL(不同数据不同过期时间)
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.builder(factory)
.withInitialCacheConfigurations(Map.of(
"short_ttl", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)),
"long_ttl", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1))
)).build();
}
三、避坑指南:这些雷区千万别踩!
1. 自调用失效问题
// ❌ 错误:类内部调用不走代理
public void updateProductPrice(Long id) {
// 内部调用不会触发缓存清除
this.clearCache(id);
}
@CacheEvict(value="products", key="#id")
private void clearCache(Long id) {}
// ✅ 正确:通过AopContext解决
@EnableAspectJAutoProxy(exposeProxy = true)
public void updateProductPrice(Long id) {
((ProductService) AopContext.currentProxy()).clearCache(id);
}
2. 缓存穿透防护
// 空值缓存策略
@Cacheable(value="users", key="#id", unless = "#result == null")
public User getUser(Long id) {
User user = userDao.findById(id);
if(user == null) {
// 缓存空对象(设置短TTL)
return new NullUser();
}
return user;
}
3. 事务与缓存顺序
// ❌ 缓存更新可能发生在事务回滚前
@Transactional
@CacheEvict(value="products", key="#id")
public void updateWithRisk(Long id) {
// 数据库操作(可能失败回滚)
}
// ✅ 正确:事务提交后清除缓存
@CacheEvict(value="products", key="#id", afterInvocation = true)
@Transactional
public void safeUpdate(Long id) {
// 业务逻辑
}
四、性能核弹:异步缓存模式
// 1. 配置异步缓存
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setAsyncCacheLoader(new AsyncCacheLoader<Object, Object>() {
@Override
public CompletableFuture<Object> load(Object key, Executor executor) {
return CompletableFuture.supplyAsync(() -> {
// 异步加载数据
return heavyLoadOperation(key);
}, executor);
}
});
return manager;
}
// 2. 异步调用
@Cacheable(value = "async_cache", key = "#id")
public CompletableFuture<Product> getProductAsync(Long id) {
// 立即返回Future对象
}
实战场景:电商库存缓存方案
@Service
public class InventoryService {
// 组合注解:先删缓存再更新DB
@Caching(evict = {
@CacheEvict(value = "stock", key = "#skuId"),
@CacheEvict(value = "hot_items", allEntries = true)
})
@Transactional
public void updateStock(String skuId, int delta) {
inventoryDao.updateStock(skuId, delta);
}
// 热点商品特殊处理:本地缓存+Redis二级缓存
@Cacheable(value = "stock", key = "#skuId", cacheManager = "compositeCacheManager")
public Integer getStock(String skuId) {
return inventoryDao.getStock(skuId);
}
}
性能对比:
|
方案 |
QPS |
平均响应 |
|
直接查DB |
120 |
45ms |
|
普通Redis缓存 |
3500 |
8ms |
|
本地+Redis二级 |
8500 |
2ms |
结语:缓存的艺术
Spring Cache 的精髓在于平衡:
- 用unless过滤不必要的数据
- 用sync保护数据库
- 用Composite实现多级加速
- 用afterInvocation确保数据一致性
缓存不是银弹,但用对场景能让性能提升百倍!记住:缓存命中率 > 80% 才是有效缓存,否则立即检查你的Key设计!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
您必须登录才能参与评论!
立即登录



缓存策略很实用👍
避坑指南很关键
这些操作能提效呢👏
收藏了,感谢分享
这和直接写代码还有啥区别
缓存技巧用对了,真是性能提升器!
缓存的世界原来这么大
Spring Cache用法真多😃