Java Spring

发布于

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) { ... }