You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Spring Boot默认Cache实现批量缓存用户供单查复用?

解决Spring Boot Cache批量缓存单用户条目问题

你的核心问题是getUsers()缓存的是整个用户列表,而getUser(id)的缓存键是用户ID,两者缓存条目不互通,导致单用户查询仍会触发第三方API调用。下面提供一种直接可行的实现方式:

实现思路

在getUsers()方法获取到用户列表后,手动通过CacheManager将每个用户以其ID为键存入users缓存,这样后续调用getUser(id)时就能直接命中缓存。

代码实现

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    private final CacheManager cacheManager;

    // 构造注入CacheManager
    public UserService(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @Cacheable("users")
    public List<User> getUsers() {
        // 调用第三方API获取完整用户列表
        List<User> userList = fetchUserListFromThirdParty();
        
        // 获取指定缓存实例,批量存入单用户缓存条目
        Cache usersCache = cacheManager.getCache("users");
        if (usersCache != null) {
            userList.forEach(user -> usersCache.put(user.getId(), user));
        }
        
        return userList;
    }

    @Cacheable(value = "users", key = "#id")
    public User getUser(Long id) {
        // 仅当缓存未命中时才调用第三方API
        return fetchSingleUserFromThirdParty(id);
    }

    // 模拟第三方API调用逻辑
    private List<User> fetchUserListFromThirdParty() {
        // 实际场景替换为调用外部/users接口
        return List.of(new User(1L, "Alice"), new User(2L, "Bob"), new User(3L, "Charlie"));
    }

    private User fetchSingleUserFromThirdParty(Long id) {
        // 实际场景替换为调用外部/users/{id}接口
        return new User(id, "User_" + id);
    }
}

// 用户实体类示例
class User {
    private Long id;
    private String name;

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getter方法
    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

关键说明

  1. 缓存互通逻辑:getUsers()在缓存整个列表的同时,遍历用户列表,将每个用户以id为键存入users缓存,与getUser(id)的缓存键规则保持一致。
  2. 兼容性:该方案适配Spring Boot默认的ConcurrentMapCacheManager,也支持Redis等其他缓存实现(只要通过CacheManager抽象层操作即可)。
  3. 缓存一致性:如果后续需要更新用户数据,需在更新方法上添加@CacheEvict注解,同时清理列表缓存和单用户缓存,例如:
    @CacheEvict(value = "users", key = "#user.id")
    @CacheEvict(value = "users", key = "#root.methodName") // 清理getUsers()对应的列表缓存
    public void updateUser(User user) {
        // 更新第三方API数据逻辑
    }
    

内容的提问来源于stack exchange,提问作者user2199973

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 02:55:17