Spring Boot Caching如何实现Redis批量缓存查询、回源及结果合并?
Spring Cache 基于Redis实现批量查询、未命中补查、结果合并方案(Spring原生实现)
不需要自定义装饰器,直接使用Spring Data Redis与Spring Cache原生API即可实现所有需求,完全不需要额外引入第三方组件,也不用修改原有Service层代码。
前置准备
首先完成基础配置:
- 项目引入
spring-boot-starter-cache、spring-boot-starter-data-redis依赖 - 启动类添加
@EnableCaching注解开启缓存能力 - 配置文件中完成Redis连接参数配置
- 给
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
相关产品推荐
相关产品推荐

