分页列表缓存,你真的会吗

这篇具有很好参考价值的文章主要介绍了分页列表缓存,你真的会吗。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

开源中国的红薯哥写了很多关于缓存的文章,其中多级缓存思路,分页列表缓存这些知识点给了我很大的启发性。

写这篇文章,我们聊聊分页列表缓存,希望能帮助大家提升缓存技术认知。

1 直接缓存分页列表结果

显而易见,这是最简单易懂的方式。

分页列表缓存,你真的会吗

我们按照不同的分页条件来缓存分页结果 ,伪代码如下:

public List<Product> getPageList(String param,int page,int size) {
  String key = "productList:page:" + page + ”size:“ + size + 
               "param:" + param ;
  List<Product> dataList = cacheUtils.get(key);
  if(dataList != null) {
    return dataList;
  }
  dataList = queryFromDataBase(param,page,size);
  if(dataList != null) {
       cacheUtils.set(key , dataList , Constants.ExpireTime);
  }
} 

这种方案的优点是工程简单,性能也快,但是有一个非常明显的缺陷基因:列表缓存的颗粒度非常大

假如列表中数据发生增删,为了保证数据的一致性,需要修改分页列表缓存。

有两种方式 :

1、依靠缓存过期来惰性的实现 ,但业务场景必须包容;

2、使用 Redis 的 keys 找到该业务的分页缓存,执行删除指令。 但 keys 命令对性能影响很大,会导致 Redis 很大的延迟 。

生产环境使用 keys 命令比较危险,发生事故的几率高,非常不推荐使用

2 查询对象ID列表,再缓存每个对象条目

缓存分页结果虽然好用,但缓存的颗粒度太大,保证数据一致性比较麻烦。

所以我们的目标是更细粒度的控制缓存

分页列表缓存,你真的会吗

我们查询出商品分页对象ID列表,然后为每一个商品对象创建缓存 , 通过商品ID和商品对象缓存聚合成列表返回给前端。

伪代码如下:分页列表缓存,你真的会吗

核心流程:

1、从数据库中查询分页 ID 列表

// 从数据库中查询分页商品 ID 列表
List<Long> productIdList = queryProductIdListFromDabaBase(
                           param, 
                           page, 
                           size);

对应的 SQL 类似:

SELECT id FROM products
ORDER BY id 
LIMIT (page - 1) * size , size 

2、批量从缓存中获取商品对象

Map<Long, Product> cachedProductMap = cacheUtils.mget(productIdList);

假如我们使用本地缓存,直接一条一条从本地缓存中聚合也极快。

假如我们使用分布式缓存,Redis 天然支持批量查询的命令 ,比如 mget ,hmget 。

3、组装没有命中的商品ID

List<Long> noHitIdList = new ArrayList<>(cachedProductMap.size());
for (Long productId : productIdList) {
     if (!cachedProductMap.containsKey(productId)) {
         noHitIdList.add(productId);
     }
}

因为缓存中可能因为过期或者其他原因导致缓存没有命中的情况,所以我们需要找到哪些商品没有在缓存里。

4、批量从数据库查询未命中的商品信息列表,重新加载到缓存

首先从数据库里批量查询出未命中的商品信息列表 ,请注意是批量

List<Product> noHitProductList = batchQuery(noHitIdList);

参数是未命中缓存的商品ID列表,组装成对应的 SQL,这样性能更快 :

SELECT * FROM products WHERE id IN
                         (1,
                          2,
                          3,
                          4);

然后这些未命中的商品信息存储到缓存里 , 使用 Redis 的 mset 命令。

//将没有命中的商品加入到缓存里
Map<Long, Product> noHitProductMap =
         noHitProductList.stream()
         .collect(
           Collectors.toMap(Product::getId, Function.identity())
         );
cacheUtils.mset(noHitProductMap);
//将没有命中的商品加入到聚合map里
cachedProductMap.putAll(noHitProductMap);

5、 遍历商品ID列表,组装对象列表

for (Long productId : productIdList) {
    Product product = cachedProductMap.get(productId);
    if (product != null) {
       result.add(product);
    }
}

当前方案里,缓存都有命中的情况下,经过两次网络 IO ,第一次数据库查询 IO ,第二次 Redis 查询 IO , 性能都会比较好。

所有的操作都是批量操作,就算有缓存没有命中的情况,整体速度也较快。

查询对象ID列表,再缓存每个对象条目“ 这个方案比较灵活,当我们查询对象ID列表,可以不限于数据库,还可以是搜索引擎,Redis 等等。

下图是开源中国的搜索流程:

分页列表缓存,你真的会吗

精髓在于:搜索的分页结果只包含业务对象 ID ,对象的详细资料需要从缓存 + MySQL 中获取。

3 缓存对象ID列表,同时缓存每个对象条目

笔者曾经重构过类似朋友圈的服务,进入班级页面 ,瀑布流的形式展示班级成员的所有动态。

分页列表缓存,你真的会吗

我们使用推模式将每一条动态 ID 存储在 Redis ZSet 数据结构中 。Redis ZSet 是一种类型为有序集合的数据结构,它由多个有序的唯一的字符串元素组成,每个元素都关联着一个浮点数分值。

ZSet 使用的是 member -> score 结构 :

  • member : 被排序的标识,也是默认的第二排序维度( score 相同时,Redis 以 member 的字典序排列)
  • score : 被排序的分值,存储类型是 double

分页列表缓存,你真的会吗

如上图所示:ZSet 存储动态 ID 列表 , member 的值是动态编号 , score 值是创建时间

通过 ZSet 的 ZREVRANGE 命令就可以实现分页的效果。

ZREVRANGE 是 Redis 中用于有序集合(sorted set)的命令之一,它用于按照成员的分数从大到小返回有序集合中的指定范围的成员。

分页列表缓存,你真的会吗

为了达到分页的效果,传递如下的分页参数 :

分页列表缓存,你真的会吗

通过 ZREVRANGE 命令,我们可以查询出动态 ID 列表。

查询出动态 ID 列表后,还需要缓存每个动态对象条目,动态对象包含了详情,评论,点赞,收藏这些功能数据 ,我们需要为这些数据提供单独做缓存配置。

分页列表缓存,你真的会吗

无论是查询缓存,还是重新写入缓存,为了提升系统性能,批量操作效率更高。

缓存对象结构简单,使用 mget 、hmget 命令;若结构复杂,可以考虑使用 pipleline,Lua 脚本模式 。笔者选择的批量方案是 Redis 的 pipleline 功能。

我们再来模拟获取动态分页列表的流程:

  1. 使用 ZSet 的 ZREVRANGE 命令 ,传入分页参数,查询出动态 ID 列表 ;
  2. 传递动态 ID 列表参数,通过 Redis 的 pipleline 功能从缓存中批量获取动态的详情,评论,点赞,收藏这些功能数据 ,组装成列表 。

4 总结

本文介绍了实现分页列表缓存的三种方式:

  1. 直接缓存分页列表结果

  2. 查询对象ID列表,只缓存每个对象条目

  3. 缓存对象ID列表,同时缓存每个对象条目

这三种方式是一层一层递进的,要诀是:

细粒度的控制缓存批量加载对象


如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!

分页列表缓存,你真的会吗文章来源地址https://www.toymoban.com/news/detail-456193.html

到了这里,关于分页列表缓存,你真的会吗的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • flask+分页查询列表显示

    模版动态加载数据 页面显示效果

    2024年02月12日
    浏览(35)
  • 通过redis进行缓存分页,通过SCAN扫描进行缓存更新

    问题: 当我们要添加缓存时,如果我们用了PageHelper时,PageHelper只会对查询语句有效(使用到sql的查询),那么如果我们把查询到的数据都添加到缓存时,就会无法进行分页; 此时我们选择将分页后的数据加入缓存,前端传入page和count表示查询页数和个数,我们将其拼接到查

    2024年02月13日
    浏览(47)
  • 全球&中国 AI 大模型 ( LLM ) 列表

    AI 大模型(Large Language Model,简称LLM)是一种人工智能技术,通过深度学习算法训练大规模数据集来生成自然语言文本(如文章、对话等)。该技术的应用范围非常广泛,包括自然语言处理、机器翻译、文本生成、问答系统等。目前,AI 大模型已成为人工智能领域的一个热点

    2024年02月13日
    浏览(57)
  • MyBatis --- 缓存、逆向工程、分页插件

    一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问 使一级缓存失效的四种情况: 1、不同的SqlSession对应不同的一级缓存 2、同一个SqlSession但是查询条件不同 3、同一个SqlSession两次查询期

    2023年04月09日
    浏览(45)
  • 前端vue简单好用的上拉加载下拉刷新组件,支持列表分页 本地分页

    前端vue简单好用的上拉加载下拉刷新组件,支持列表分页 本地分页, 阅读全文下载完整代码请关注微信公众号: 前端组件开发 效果图如下:         #### 使用方法 ```使用方法 !-- pullDown:下拉刷新 back-top: 回到顶部  -- ccPullScroll class=\\\"pullScrollView\\\" ref=\\\"pullScroll\\\" :back-top=\\\"true\\\" :pullDo

    2024年02月08日
    浏览(58)
  • 若依框架列表分页功能失效解决办法

    在近期针对若依框架进行开发的过程中,发现通过controller层对查询出的列表数据进行修改封装(将部分数据字段做了码值映射处理,整体条数未发生变化)后,分页功能会出现问题:查询列表的时候明明有上百条数据,但却显示total只有10条,且只有一页。经过debug分析发现主

    2024年02月16日
    浏览(44)
  • 微信小程序 列表多选 下拉分页 滑动切换分类

    1、卡片列表 2、分页(下拉页面加载分页数据) 3、分类(页面间互不干扰,数据也不干扰) 4、左右滑动可切换分类 5、列表搜索 6、单选模式(默认单选模式,即点击卡片,回写所选数据) 7、 多选 模式(实现微信聊天多选效果) 长按 列表或 点击多选 ,进入多选模式;

    2024年02月03日
    浏览(46)
  • 给Dedecms文章列表分页标题加上序号的方法示例

    为dedecms文章分页标题加上序号,小编提醒:本教程只在dedecms5.1版本下测试通过,如果您想在其它版本试验,请先备份原文件! 改模板文件inc_archives_view.php就OK了 代码如下: 列表页的标题也有办法了 用{dede:pagelist listsize=\\\'0\\\' listitem=\\\'pageno\\\' function=\\\'html2text(@me)\\\'/}可以调用第几页那个

    2024年02月02日
    浏览(44)
  • Django实战项目-学习任务系统-查询列表分页显示

    接着上期代码框架,6个主要功能基本实现,剩下的就是细节点的完善优化了。 接着优化查询列表分页显示功能,有很多菜单功能都有查询列表显示页面情况,如果数据量多,不分页显示的话,页面展示效果就不太好。 本次增加查询列表分页显示功能,对一个查询列表功能进

    2024年02月05日
    浏览(50)
  • Android Jetpack Compose 中的分页与缓存展示

    在几乎任何类型的移动项目中,移动开发人员在某个时候都会处理分页数据。如果数据列表太大,无法一次从服务器检索完毕,这就是必需的。因此,我们的后端同事为我们提供了一个端点,返回分页数据列表,并期望我们知道如何在客户端处理它。 在本文中,我们将重点介

    2024年02月13日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包