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

Spring Boot Caching如何实现Redis批量缓存查询、回源及结果合并?

Spring Cache 基于Redis实现批量查询、未命中补查、结果合并方案(Spring原生实现)

不需要自定义装饰器,直接使用Spring Data Redis与Spring Cache原生API即可实现所有需求,完全不需要额外引入第三方组件,也不用修改原有Service层代码。


前置准备

首先完成基础配置:

  1. 项目引入spring-boot-starter-cache、spring-boot-starter-data-redis依赖
  2. 启动类添加@EnableCaching注解开启缓存能力
  3. 配置文件中完成Redis连接参数配置
  4. 给RedisTemplate配置Jackson序列化规则,避免对象序列化乱码、反序列化失败问题

Repository层改造实现(完整代码)

import org.springframework.cache.annotation.CacheConfig;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

// 统一配置缓存前缀,方便后续批量管理缓存
@CacheConfig(cacheNames = "bookCache")
@Repository
public class MyRepository {

    @Resource
    private RedisTemplate<String, Book> redisTemplate;
    // 原有数据库操作层,替换为你自己的DB查询组件即可
    @Resource
    private BookMapper bookMapper;

    public List<Book> getBooks(List<String> ids) {
        // 构造所有id对应的缓存key,规则可自定义,这里用 缓存前缀:id 格式
        List<String> cacheKeys = ids.stream()
                .map(id -> "bookCache:" + id)
                .collect(Collectors.toList());

        // 1. 解决第一个问题:调用Spring Redis原生API批量查询缓存
        List<Book> cachedBooks = redisTemplate.opsForValue().multiGet(cacheKeys);

        // 筛选缓存未命中的id,同时暂存已命中的缓存结果
        List<String> missIds = new ArrayList<>();
        Map<String, Book> resultMap = new HashMap<>();
        for (int i = 0; i < ids.size(); i++) {
            String id = ids.get(i);
            Book cached = cachedBooks.get(i);
            if (cached != null) {
                resultMap.put(id, cached);
            } else {
                missIds.add(id);
            }
        }

        // 2. 解决第二个问题:仅存在未命中id时才调用数据库查询
        if (!missIds.isEmpty()) {
            // 此处为原有批量查DB的逻辑,仅传入未命中的id列表
            List<Book> dbBooks = bookMapper.selectBatchIds(missIds);
            // 把DB查询到的结果写入缓存,下次请求直接命中
            Map<String, Book> dbBookMap = dbBooks.stream()
                    .collect(Collectors.toMap(Book::getId, book -> book));
            redisTemplate.opsForValue().multiSet(dbBookMap);
            // DB结果合并到总结果集
            resultMap.putAll(dbBookMap);
        }

        // 3. 解决第三个问题:按入参id顺序合并结果返回给Service层
        return ids.stream()
                .map(resultMap::get)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}

关键逻辑说明

  • 批量查询缓存:使用Spring Data Redis原生提供的multiGet方法,单次请求Redis即可获取所有key对应的值,性能远高于循环单查
  • 未命中id筛选:遍历批量缓存查询结果,筛选出对应值为null的id,仅将这部分id传入DB查询,无未命中时完全不会触发DB请求
  • 结果合并:用Map存储所有已命中的缓存+DB查询结果,最后按原始传入的id顺序组装返回,既保证结果完整性,也符合业务层对返回值顺序的常规预期

提示:可以根据业务需要给缓存添加过期时间,避免冷数据长期占用Redis内存,写入缓存时可替换为multiSetIfAbsent或者单独给每个key设置过期时间即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:27:02