批量缓存(一)

本文介绍了在Spring中使用Redis进行Cache-Aside和Cache-Through缓存策略,并指出传统旁路缓存的局限。通过创建新的批量缓存框架,解决批量查询时的性能问题,提供更高效的缓存解决方案。
摘要由CSDN通过智能技术生成

之前已经完成了redis的配置和常用工具类的编写redis配置以及相关工具类
本文介绍如何在具体业务中使用。
缓存的使用方式通常分为两种:Cache-Aside(旁路缓存)和Cache-Through(缓存即数据源)。简而言之,前者通常用于读取操作,而后者则适用于读写操作。
盘路缓存
对于读,首先从缓存读取数据,如果没有命中则回源数据库读取并更新缓存。对于写操作,先写 数据库,再写缓存。
逻辑代码:

//读操作
data = Cache.get(key);
if(data == NULL)
{
    data = SoR.load(key);
    Cache.set(key, data);
}

//写操作
if(SoR.save(key, data))
{
    Cache.set(key, data);
}

在spring中提供了好用的盘路缓存框架spring-cache。只需要写load逻辑。加上个注解,就能实现盘路缓存的效果。
在这里插入图片描述

这种缓存仍然有个缺陷,在极端情况下。我需要获取一批帖子的信息,碰巧所有的帖子缓存都失效了,都需全部重新加载。

        for (Long postId : postIdList) {
            Post post= postCache.getById(postId);
            post.add(post);
        }

那么这样一个本来性能很高的循环,就等同于全部查了数据库。
批量缓存查询
对于这种批量查询缓存的需求,传统的旁路缓存框架无法达到我们的需求。我们需要让他能够批量的get or load。
批量get发现没有的数据,再批量的load一次,这样和redis以及数据库的交互都只会有一次。

    @Autowired
   private PostService postService;
    @Cacheable(cacheNames = "post", key = "#postId")
    public Post getById(Long postId){
      return  postService.getById(postId);
    }

    private static final String BASE_KEY = "base:";
    private static final String POST_INFO_STRING = "post:info:";

    /**
     * 获取帖子信息,采用Redis缓存模式
     */
    public Map<Long, Post> getPostInfoBatch(Set<Long> postIds) {
        // 批量组装key
        List<String> keys = postIds.stream().map(a -> String.format(BASE_KEY, POST_INFO_STRING, a)).collect(Collectors.toList());
        // 批量get
        List<Post> mget = RedisUtils.mget(keys, Post.class);
        Map<Long, Post> map = mget.stream().filter(Objects::nonNull).collect(Collectors.toMap(Post::getId, Function.identity()));
        // 发现差集——还需要从数据库中加载的postId
        List<Long> needLoadPostIdList = postIds.stream().filter(a -> !map.containsKey(a)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(needLoadPostIdList)) {
            // 批量load
            List<Post> needLoadPostList = postService.listByIds(needLoadPostIdList);
            Map<String, Post> redisMap = needLoadPostList.stream().collect(Collectors.toMap(a -> String.format(BASE_KEY, POST_INFO_STRING, a), Function.identity()));

            // 将数据批量存入Redis,并设置过期时间(这里假设为5分钟)
            RedisUtils.mset(redisMap, 5 * 60);
            //加载回redis
            map.putAll(needLoadPostList.stream().collect(Collectors.toMap(Post::getId, Function.identity())));
        }
        return map;
    }

RedisUtils参考前文redis配置以及相关工具类
总结
通过本文的剖析,我们深入了解了缓存的常用使用方式,并探讨了传统旁路缓存框架的局限性。鉴于这些不足,实现了新的批量缓存框架,旨在提供更高效、更可靠的缓存解决方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值