Spring Boot缓存策略@Cacheable使用
Spring Cache 提供声明式缓存抽象,简化缓存实现。
开启缓存
Java
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
缓存配置
YAML
spring:
cache:
type: redis
redis:
time-to-live: 3600000 # 1小时
cache-null-values: false
key-prefix: "app:"
use-key-prefix: true
@Cacheable注解
查询时先查缓存,命中则返回,未命中则执行方法并缓存结果。
Java
@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
log.info("查询数据库: {}", id);
return userRepository.findById(id).orElse(null);
}
// 条件缓存
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public User getUserByIdNotNull(Long id) {
return userRepository.findById(id).orElse(null);
}
// SpEL表达式
@Cacheable(value = "users", key = "#user.id + ':' + #user.type")
public User getComplexKey(User user) {
return userRepository.findById(user.getId()).orElse(null);
}
}
@CachePut注解
每次都执行方法,并更新缓存。
Java
@Service
public class UserService {
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
@CachePut(value = "users", key = "#result.id")
public User createUser(User user) {
return userRepository.save(user);
}
}
@CacheEvict注解
删除缓存条目。
Java
@Service
public class UserService {
// 删除单个缓存
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
// 删除所有缓存
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
// 清空users缓存
}
// 方法执行前删除
@CacheEvict(value = "users", key = "#id", beforeInvocation = true)
public void deleteUserBefore(Long id) {
// 即使方法异常也会删除缓存
}
}
@Caching组合注解
Java
@Service
public class OrderService {
@Caching(
put = @CachePut(value = "orders", key = "#order.id"),
evict = @CacheEvict(value = "userOrders", key = "#order.userId")
)
public Order createOrder(Order order) {
return orderRepository.save(order);
}
}
自定义KeyGenerator
Java
@Component
public class CustomKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getSimpleName()).append(":");
sb.append(method.getName()).append(":");
for (Object param : params) {
sb.append(param.toString()).append(",");
}
return sb.toString();
}
}
// 使用自定义KeyGenerator
@Cacheable(value = "users", keyGenerator = "customKeyGenerator")
public User getUser(String name, Integer age) {
return userRepository.findByNameAndAge(name, age);
}
缓存注解对比
| 注解 | 作用 | 执行时机 |
|---|---|---|
| @Cacheable | 查询缓存 | 方法执行前检查 |
| @CachePut | 更新缓存 | 方法执行后更新 |
| @CacheEvict | 删除缓存 | 方法执行后删除 |
注意事项
@Cacheable不支持内部调用,需通过代理对象调用才能生效。
Java
@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
// 错误:内部调用缓存不生效
public User getUserWrong(Long id) {
return getUser(id); // 直接调用,缓存失效
}
// 正确:通过代理对象调用
@Autowired
private UserService self;
public User getUserRight(Long id) {
return self.getUser(id); // 代理调用,缓存生效
}
}
要点总结
- @Cacheable适合读多写少场景
- @CachePut用于数据更新后刷新缓存
- @CacheEvict用于数据删除时清理缓存
- 注意内部调用和序列化问题
📝 发现内容有误?点击此处直接编辑