以下是 @Cacheable 和 @CachePut 的详细对比,涵盖功能、执行流程、适用场景、参数配置及代码示例:
1. 核心对比表格
| 特性 | @Cacheable | @CachePut | 
|---|---|---|
| 作用 | 缓存方法的返回结果,避免重复计算 | 执行方法并更新缓存,不覆盖原有缓存 | 
| 执行流程 | 缓存命中:直接返回缓存值,不执行方法 未命中:执行方法,缓存结果 | 始终执行方法,并将结果更新到缓存 | 
| 适用场景 | 查询操作(如 get方法) | 更新操作(如 save、update方法) | 
| 缓存行为 | 覆盖原有缓存值(或按条件更新) | 追加或覆盖缓存值(不删除原有数据) | 
| 是否执行方法 | 仅当缓存未命中时执行 | 始终执行方法 | 
| 性能影响 | 最优(减少重复计算) | 稍高(需同时执行方法和更新缓存) | 
2. 详细对比说明
(1) @Cacheable
- 核心功能:根据方法参数生成缓存键(key),若缓存中存在对应键的值,则直接返回缓存值,否则执行方法并将结果存入缓存。
- 适用场景:查询操作(如从数据库或远程服务获取数据)。
- 参数配置: - value/cacheNames:指定缓存名称(必填)。
- key:自定义缓存键(如- #id)。
- condition:条件判断是否缓存(如- #result != null)。
- unless:条件判断是否不缓存(如- #result == null)。
 
(2) @CachePut
- 核心功能:无论缓存是否存在,始终执行方法,并将方法结果更新到缓存中。
- 适用场景:更新操作(如保存或更新数据后同步更新缓存)。
- 参数配置: - value/cacheNames:指定缓存名称(必填)。
- key:自定义缓存键(如- #user.id)。
- condition/unless:控制是否更新缓存。
 
3. 代码示例对比
场景:用户信息的增删改查
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;// @Cacheable:缓存查询结果@Cacheable(value = "userCache", key = "#id")public User getUserById(Long id) {System.out.println("从数据库查询用户ID:" + id);return userMapper.selectUserById(id);}// @CachePut:更新缓存(同时更新数据库)@CachePut(value = "userCache", key = "#user.id")public User updateUser(User user) {System.out.println("更新用户信息并缓存:ID=" + user.getId());userMapper.updateUser(user); // 更新数据库return user;}
}
执行流程对比
| 方法 | @Cacheable流程 | @CachePut流程 | 
|---|---|---|
| getUserById(1) | 1. 检查 userCache:1是否存在2. 存在则返回缓存,不执行方法 3. 不存在则执行方法并缓存结果 | 不适用 | 
| updateUser(user) | 不适用 | 1. 始终执行方法(更新数据库) 2. 将返回结果存入 userCache:user.id | 
4. 关键参数对比
@Cacheable
| 参数 | 描述 | 示例值 | 
|---|---|---|
| value | 缓存名称(必填) | "userCache" | 
| key | 缓存键(默认 #method.name + #root.args) | "user_" + #id | 
| condition | 只有满足条件时才缓存结果 | #result != null | 
| unless | 满足条件时不缓存结果 | #result.age < 18 | 
@CachePut
| 参数 | 描述 | 示例值 | 
|---|---|---|
| value | 缓存名称(必填) | "userCache" | 
| key | 缓存键(默认 #method.name + #root.args) | "user_" + #user.id | 
| condition | 只有满足条件时才更新缓存 | #user.name != null | 
5. 注意事项
-  组合使用场景: -  更新操作:通常需要 @CachePut和@CacheEvict的组合,例如:@CacheEvict(value = "userCache", key = "#id") // 先删除旧缓存 @CachePut(value = "userCache", key = "#user.id") // 再存入新数据 public User updateUser(User user, Long id) { ... }
-  新增操作:使用 @CachePut将新数据存入缓存(如insertUser方法)。
 
-  
-  缓存一致性: - 对于更新操作,需确保数据库和缓存同时更新,避免数据不一致。
- 使用@CacheEvict清除旧缓存,再通过@CachePut存入新数据。
 
-  性能权衡: - @CachePut会强制执行方法,需评估是否影响性能。
- 对于高频写操作,需结合缓存过期策略(如time-to-live)。
 
6. 总结表格
| 注解 | 作用 | 是否执行方法 | 适用场景 | 关键参数 | 
|---|---|---|---|---|
| @Cacheable | 缓存方法结果,减少重复计算 | 仅当缓存未命中时执行 | 查询操作( get) | value,key,condition | 
| @CachePut | 更新缓存,确保数据一致性 | 始终执行方法 | 更新操作( update、save) | value,key,condition | 
通过以上对比,可以清晰理解这两个注解的差异和使用场景,从而在实际开发中合理选择和组合使用。