go-zero(十五)结合Redis:实现高效分页列表

go zero 结合redis实现分页列表

在实际开发中,分页列表 是一个非常常见的需求,尤其在面对大量数据时,通过分页可以有效减轻服务器和数据库的压力,提高用户体验。本篇文章将通过go zero 和 Redis 的结合,提供一个高效、灵活的分页列表实现方案,涵盖 基本分页逻辑Redis 缓存结合常见优化方法

一、需求分析和实现方案

1.需求

在一个社交媒体平台中,每个用户可以发布多篇文章,当用户浏览文章时,需要分页加载他们的内容。考虑以下场景:

  1. 发布时间点赞数 排序。
  2. 数据需要 支持分页,并在高并发情况下保持高性能。
  3. 结合 Redis 缓存 提升效率,减少数据库查询压力。
  4. 防止重复数据 或分页游标不一致问题。

2. 分页实现方案

分页通常分为两种实现方式

  • 基于偏移量(Offset-based Pagination): 使用 SQL 的 LIMITOFFSET 实现,适合小型数据集。
  • 基于游标(Cursor-based Pagination): 通过某个字段(如 idpublish_time)来标记分页起点,更适合大型数据集和高并发场景。

在本文中,我们主要讨论 游标分页 的实现。

完整的分页步骤总结:

  • 参数校验:确保用户输入的参数有效,并设置合理的默认值。
  • **排序字段设置 **:根据排序方式选择排序字段,确定游标的意义。
  • **缓存查询 **:尝试从缓存中获取数据,优先使用缓存提升性能。
  • **数据库查询 **:当缓存未命中时,从数据库查询数据,确保数据一致性。
  • **数据排序 **:根据排序字段对数据进行排序,确保结果符合业务逻辑。
  • **边界处理 **:防止分页数据重复,同时正确处理最后一页标记。
  • **缓存更新 **:异步更新缓存,提升后续查询效率。
  • **结果返回 **:封装分页数据、游标以及是否为最后一页的信息。

二、 项目设计

1.数据表设计

article 表:

CREATE TABLE `article` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `title` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '标题',
    `content` TEXT NOT NULL COMMENT '内容',
    `author_id` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '作者ID',
    `like_num` INT NOT NULL DEFAULT '0' COMMENT '点赞数',
    `publish_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间',
    PRIMARY KEY (`id`),
    INDEX `idx_author_publish_time` (`author_id`, `publish_time`)
);

2.分页接口需求

  1. 请求参数:

    • userId:用户 ID。
    • cursor:上一页的最后一个游标值(如 publish_time)。
    • pageSize:每页的记录数量。
    • sortType:排序方式(0 按发布时间排序,1 按点赞数排序)。
  2. 返回结果:

    • isEnd:是否为最后一页。
    • cursor:下一页的游标值。
    • articles:当前页的文章列表。
    • articleId : 最后一个文章ID

article.proto 文件:

syntax = "proto3";

package pb;
option go_package="./pb";

service Article {
   
   
  rpc Articles(ArticlesRequest) returns (ArticlesResponse);
}

message ArticlesRequest {
   
   
  int64 userId = 1;
  int64 cursor = 2;
  int64 pageSize = 3;
  int64 sortType = 4;
  
}

message ArticleItem {
   
   
  int64 Id = 1;
  string title = 2;
  string content = 3;
  string description = 4;
  string cover = 5;
  int64 commentCount = 6;
  int64 likeCount = 7;
  int64 publishTime = 8;
  int64 authorId = 9;
}

message ArticlesResponse {
   
   
  repeated ArticleItem articles = 1;
  bool isEnd = 2;
  int64 cursor = 3;
  int64 articleId = 4;
}


三、项目实现

为了进一步提高性能,可以使用 Redis 存储文章列表的分页缓存。这里使用 Redis 的有序集合(ZSET),根据 publish_timelike_num 排序。

1.自定义常量

const (
	SortPublishTime = iota
	SortLikeCount
)
const (
	articlesExpire = 3600 * 24 * 2
)
const (
	DefaultPageSize       = 20
	DefaultLimit          = 200
	DefaultSortLikeCursor = 1 << 30
)

2.通过用户ID查询文章

func (m *customArticleModel) ArticlesByUserId(ctx context.Context, userId, likeNum int64, pubTime, sortField string, limit int) ([]*Article, error) {
   
   

	//var anyField any
	var sql string

	if sortField == "like_num" {
   
   
		//anyField = likeNum
		//sql = fmt.Sprintf("select "+articleRows+" from "+m.table+" where user_id=? and like_num < ? order by %s desc limit ?", sortField)
		sql = fmt.Sprintf("select %s from %s  where `author_id`=? and like_num < %d order by %s desc limit ?", articleRows, m.table, likeNum, sortField)

	} else {
   
   
		//anyField = pubTime
		sql = fmt.Sprintf("select %s from %s  where `author_id`=? and publish_time < '%s' order by %s desc limit ?", articleRows, m.table, pubTime, sortField)
	}
	var articles []*Article
	err := m.QueryRowsNoCacheCtx(ctx, &articles, sql, userId, limit)
	if err != nil {
   
   
		return 
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值