惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
量子位
A
Arctic Wolf
L
Lohrmann on Cybersecurity
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
WordPress大学
WordPress大学
V
Vulnerabilities – Threatpost
博客园 - Franky
C
Cyber Attacks, Cyber Crime and Cyber Security
The Cloudflare Blog
Last Week in AI
Last Week in AI
The Hacker News
The Hacker News
I
Intezer
J
Java Code Geeks
P
Privacy International News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Secure Thoughts
Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
S
Securelist
Security Latest
Security Latest
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
Jina AI
Jina AI
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
博客园_首页
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Exploit Database - CXSecurity.com
雷峰网
雷峰网
T
Tenable Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Privacy & Cybersecurity Law Blog
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 【当耐特】
T
Threat Research - Cisco Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
MongoDB | Blog
MongoDB | Blog
D
DataBreaches.Net
N
News | PayPal Newsroom
Google Online Security Blog
Google Online Security Blog
K
Kaspersky official blog
H
Help Net Security
宝玉的分享
宝玉的分享
罗磊的独立博客
Webroot Blog
Webroot Blog
月光博客
月光博客
B
Blog RSS Feed
Recorded Future
Recorded Future

Chenxu's Blog

RAG检索优化:从 68% 到 82.2% 学习深度学习 北邮计算机研究生选课指北 学习机器学习 上海篇 提出一个好问题 写代码的环境 选购一台合适的设备 计算机的第零课 序言 内蒙古篇 山东篇 一篇对transformers的疑惑 浅析GPUStack 浅谈后端项目分层 浙江篇 河南篇 一些三端协同的开发工具记录 浅谈编程语言中的 GC 在 Windows 上安装 Rust 美化博客 消息队列 MyBatis 现代交换原理2024年题目 回忆版 北邮计科本科课程指北 ClkLog埋点用户分析系统研究报告 大数据梧桐实验分享 大数据HBase实验分享 国产向量数据库研究实践 —— 基于 Milvus 的电影推荐系统 服务器环境配置 大数据HDFS实验分享 SSE多服务之间推送数据 数据库系统原理 操作系统 编译原理 手把手教你gozero从开发到部署 (番外篇): 介绍 gtodolist 前端项目 天津篇 北京篇 手把手教你gozero从开发到部署 (5): gtodolist 之任务的删除 前端相关问题 vue3 + element-plus学习 git相关命令 人工智能原理 使用 MongoTemplate 时开启事务 MySQL Redis 力扣刷题笔记之动态规划 记录一次 VSCode 出现的各种奇怪的问题 记录平时用到的 windows 右键管理 记录平时使用的 linux 的指令 安装 gstore 并使用 java api 手把手教你gozero从开发到部署 (3): gtodolist 之任务的创建和修改 手把手教你gozero从开发到部署 (番外篇): 记录第一次部署 CI/CD 的流程 记录完成 gtodolist 中遇到的 bug 手把手教你gozero从开发到部署 (2): gtodolist 之 user 模块开发 手把手教你gozero从开发到部署 (1): gtodolist 项目说明和环境准备 快速入门 gozero 框架 vue部署在nginx上的相关问题 记一次安装scrapy的报错 将博客部署至服务器 Java CS143: Compliers 《MySQL必知必会》读书笔记(2) 初识 GORM 初识 gin 框架 Spring 《MySQL必知必会》读书笔记(1) 本地搭建博客 🤝友链 🙋🏻‍♂️关于 Browser and Device Check
手把手教你gozero从开发到部署 (4): 在 model 中自己编写函数实现数据库分页查询
Chenxu · 2023-09-10 · via Chenxu's Blog

因为之前把所有框架都生成好了, 所以现在我们直接编写逻辑代码即可

api

task_list

internal\logic\task_list_logic.go

func (l *TaskListLogic) TaskList(req *types.ListReq) (resp *types.ListResp, err error) {
	// 准备参数, 规定默认 limit 为 20, start 为 1
	limit, err := strconv.Atoi(req.Limit)
	if err != nil || limit <= 0 || limit > 20 {
		limit = 20
	}
	start, err := strconv.Atoi(req.Start)
	if err != nil || start <= 0 {
		start = 1
	}
	uid := ctxdata.GetUidFromCtx(l.ctx)

	listResp, err := l.svcCtx.TaskRpcClient.ListTask(l.ctx, &pb.ListReq{
		Uid:   uid,
		Limit: int64(limit),
		Start: int64(start),
	})

	if err != nil {
		return &types.ListResp{
			Status:  int(vo.ErrServerCommonError.GetErrCode()),
			Message: err.Error(),
			Error:   err.Error(),
		}, nil
	}

	resp = &types.ListResp{}
	_ = copier.Copy(resp, listResp)
	return resp, err
}

因为模板文件中没有直接实现分页查询, 所以我们需要自己在 model 层中编写分页查询的函数 (事实上, 你也可以直接修改模板文件, 这样每一次 goctl 就都会生成分页查询的函数了)

首先我们先在 model 目录中新建 my_task_model.go 文件, 这里放我们自定义的 model 函数

package model

import (
	"context"
	"fmt"
	"gorm.io/gorm"
)

var (
	cacheGtodolistTaskListPrefix = "cache:gtodolist:task:list:"
)

type (
	myTaskModel interface {
		List(ctx context.Context, uid, page, pageSize int64) ([]Task, error)
	}
)

func (m *defaultTaskModel) List(ctx context.Context, uid, page, pageSize int64) ([]Task, error) {
	key := fmt.Sprintf("%s%v:%v:%v", cacheGtodolistTaskListPrefix, uid, page, pageSize)
	var resp []Task
	err := m.QueryCtx(ctx, &resp, key, func(conn *gorm.DB, v interface{}) error {
		err := conn.Debug().Model(&Task{}).Where("uid = ?", uid).Offset(int((page - 1) * pageSize)).Limit(int(pageSize)).Find(&resp).Error
		return err
	})
	return resp, err
}

写完以后还要将该接口添加到 task_model.go

customTaskLogicModel interface {
    myTaskModel
}

rpc

list_task

internal\logic\list_task_logic.go

func (l *ListTaskLogic) ListTask(in *pb.ListReq) (*pb.ListResp, error) {
	tasks, err := l.svcCtx.TaskModel.List(l.ctx, in.Uid, in.Start, in.Limit)
	if err != nil {
		return nil, errors.Wrap(vo.ErrDBerror, "数据库查询出错")
	}

	taskResp := make([]*pb.Task, len(tasks))
	for i := 0; i < len(tasks); i++ {
		task := tasks[i]
		taskResp[i] = &pb.Task{
			Id:        task.Id,
			Title:     task.Title,
			Content:   task.Content.String,
			Status:    int32(task.Status),
			CreateAt:  task.CreatedAt.Unix(),
			StartTime: task.StartTime.Unix(),
			EndTime:   task.EndTime.Time.Unix(),
		}
	}

	return &pb.ListResp{
		Status: vo.OK,
		Data: &pb.Data{
			Task:  taskResp,
			Total: int64(len(tasks)),
		},
		Message: vo.SUCCESS,
	}, nil
}

在 redis 中我们缓存的键是 prefix:uid:page:pageSize, 所以在删除时我们需要批量删除以 prefix:uid: 为前缀的键, 所以我们再增加一个 DeleteListCache 方法来批量删除缓存, 在增加/修改/删除时要调用该方法, 这样才能确保缓存一致性

这个地方写的不太好, 以后再优化

func (l *ListTaskLogic) DeleteListCache(uid int64) {
	prefix := "cache:gtodolist:task:list:"
	listKey := fmt.Sprintf("%s%v:*", prefix, uid)
	keys, _, _ := l.svcCtx.RedisClient.Scan(0, listKey, 0)

	for _, key := range keys {
		_, _ = l.svcCtx.RedisClient.Del(key)
	}
}