👁
发布于
AI总结: 本文介绍了Spring Cache注解的使用,包括四个主要注解:@Cacheable、@CacheEvict、@CachePut和@Caching。@Cacheable用于存入缓存,@CacheEvict用于删除缓存,@CachePut用于更新缓存,@Caching用于组合多个缓存操作。具体示例展示了如何使用这些注解来实现缓存的增删改查,包括条件缓存和同步缓存等高级用法。此外,提供了常用的SpEL表达式示例,帮助开发者灵活地定义缓存键。改进建议包括增加对每个注解的性能影响分析,以及在实际项目中的最佳实践示例,以帮助开发者更好地理解和应用这些缓存策略。
Spring Cache 注解使用说明
一、核心概念
| 注解 |
作用 |
执行时机 |
典型场景 |
@Cacheable |
存入缓存 |
方法执行前 |
查询方法 |
@CacheEvict |
删除缓存 |
方法执行后/前 |
增删改方法 |
@CachePut |
更新缓存 |
方法执行后 |
更新方法 |
@Caching |
组合操作 |
方法执行前后 |
多个缓存操作 |
二、@Cacheable 详解
2.2 使用示例
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
/**
* 示例1:最简单用法
* 缓存 key 默认使用所有参数
*/
@Cacheable("users")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 示例2:指定缓存 key
*/
@Cacheable(value = "users", key = "'user:' + #id")
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 示例3:多参数组合 key
*/
@Cacheable(value = "users", key = "'user:' + #id + ':' + #type")
public User getUserByIdAndType(Long id, String type) {
return userRepository.findByIdAndType(id, type);
}
/**
* 示例4:使用对象属性作为 key
*/
@Cacheable(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
/**
* 示例5:条件缓存(满足条件才缓存)
* condition 在方法执行前判断
*/
@Cacheable(value = "users", key = "'user:' + #id", condition = "#id > 0")
public User getUserConditional(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 示例6:排除条件(满足条件不缓存)
* unless 在方法执行后判断
*/
@Cacheable(value = "users", key = "'user:' + #result.id", unless = "#result == null")
public User getUserUnless(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 示例7:同步缓存(防止缓存击穿)
*/
@Cacheable(value = "users", key = "'user:' + #id", sync = true)
public User getUserSync(Long id) {
// 多线程同时请求时,只有一个线程执行方法,其他等待缓存结果
return userRepository.findById(id).orElse(null);
}
/**
* 示例8:多缓存名称
*/
@Cacheable(cacheNames = {"users", "userDetails"}, key = "'user:' + #id")
public User getUserMultiCache(Long id) {
return userRepository.findById(id).orElse(null);
}
}
三、@CacheEvict 详解
3.2 使用示例
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
@Service
public class UserService {
/**
* 示例1:删除单个缓存
*/
@CacheEvict(value = "users", key = "'user:' + #id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
/**
* 示例2:清空整个缓存区域
*/
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
// 清空 users 下的所有缓存
}
/**
* 示例3:方法执行前删除缓存
*/
@CacheEvict(value = "users", key = "'user:' + #id", beforeInvocation = true)
public void deleteUserBefore(Long id) {
// 无论方法执行成功与否,都会删除缓存
userRepository.deleteById(id);
// 如果这里抛出异常,缓存仍然被删除
}
/**
* 示例4:条件删除
*/
@CacheEvict(value = "users", key = "'user:' + #id", condition = "#id != null && #id > 0")
public void deleteUserIfValid(Long id) {
userRepository.deleteById(id);
}
/**
* 示例5:更新后删除旧缓存(配合 @CachePut)
*/
@CacheEvict(value = "users", key = "'user:' + #id")
@CachePut(value = "users", key = "'user:' + #result.id")
public User updateUser(Long id, User newData) {
User user = userRepository.findById(id).orElseThrow();
user.setName(newData.getName());
return userRepository.save(user);
}
}
四、完整示例
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ========== 查询操作(使用 @Cacheable) ==========
@Cacheable(value = "users", key = "'user:' + #id")
public User getUser(Long id) {
System.out.println("从数据库查询用户: " + id);
return userRepository.findById(id).orElse(null);
}
@Cacheable(value = "users", key = "'user:all'")
public List<User> getAllUsers() {
System.out.println("从数据库查询所有用户");
return userRepository.findAll();
}
@Cacheable(value = "users", key = "'user:name:' + #name", unless = "#result == null")
public User getUserByName(String name) {
System.out.println("从数据库查询用户: " + name);
return userRepository.findByName(name);
}
// ========== 增删改操作(使用 @CacheEvict) ==========
@CacheEvict(value = "users", key = "'user:' + #result.id")
public User createUser(User user) {
System.out.println("创建用户: " + user.getName());
return userRepository.save(user);
}
@CacheEvict(value = "users", key = "'user:' + #id")
public void deleteUser(Long id) {
System.out.println("删除用户: " + id);
userRepository.deleteById(id);
}
@CacheEvict(value = "users", allEntries = true)
public void deleteAllUsers() {
System.out.println("删除所有用户");
userRepository.deleteAll();
}
// ========== 更新操作(@CacheEvict + @CachePut) ==========
@Caching(evict = {
@CacheEvict(value = "users", key = "'user:' + #id"), // 删除旧缓存
@CacheEvict(value = "users", key = "'user:all'") // 删除列表缓存
})
public User updateUser(Long id, User user) {
System.out.println("更新用户: " + id);
user.setId(id);
return userRepository.save(user);
}
// ========== 组合操作(使用 @Caching) ==========
@Caching(
cacheable = {
@Cacheable(value = "users", key = "'user:' + #id")
},
evict = {
@CacheEvict(value = "users", key = "'user:all'")
}
)
public User getAndClearList(Long id) {
return userRepository.findById(id).orElse(null);
}
}
五、常用 SpEL 表达式
| 表达式 |
说明 |
示例 |
#参数名 |
方法参数 |
#id, #user.id |
#result |
返回值 |
#result.id |
#root.methodName |
方法名 |
#root.methodName |
#root.target |
目标对象 |
#root.target |
#root.args[0] |
第一个参数 |
#root.args[0] |
// 使用 #result 示例
@Cacheable(value = "users", key = "#result.id", unless = "#result == null")
public User getUser(Long id) { ... }
// 使用 #root 示例
@Cacheable(value = "users", key = "#root.methodName + ':' + #id")
public User getUser(Long id) { ... }