Go-Gin-Example 第九部分 实现redis缓存

文章目录

    • 前情提要
  • 配置
  • 缓存前缀 常量
  • 缓存中` key `值问题
  • `Redis` 工具包
  • redis 使用

首先需要自己安装 redis并提前了解相关知识

前情提要

学习项目github地址,有需要可以从这里查看源码

上一部分学习笔记

配置

api.ini 中新增 redis 相关配置

...
[redis]
Host = 127.0.0.1:6379
Password =
MaxIdle = 30
MaxActive = 30
IdleTimeout = 200

缓存前缀 常量

打开 pkg/e 目录,新建 cache.go,写入内容:

package econst (CACHE_ARTICLE = "ARTICLE"CACHE_TAG     = "TAG"
)

建立常量保存,方便后续管理

缓存中key值问题

新建 service/cathe_service 目录,新建 article.go:

// Package cache_service 缓存相关服务,单个或多个文章键名
package cache_serviceimport ("github.com/kingsill/gin-example/pkg/e""strconv""strings"
)// Article 定义缓存中可能的文章键名包含的要素
type Article struct {ID    intTagID intState intPageNum  intPageSize int
}// GetArticleKey 单个文章键名
func (a *Article) GetArticleKey() string {//ARTICLE_1return e.CACHE_ARTICLE + "_" + strconv.Itoa(a.ID)
}// GetArticlesKey 多个文章键名? 一个文章信息更多的键名
func (a *Article) GetArticlesKey() string {keys := []string{e.CACHE_ARTICLE,"LIST",}if a.ID > 0 {keys = append(keys, strconv.Itoa(a.ID))}if a.TagID > 0 {keys = append(keys, strconv.Itoa(a.TagID))}if a.State >= 0 {keys = append(keys, strconv.Itoa(a.State))}if a.PageNum > 0 {keys = append(keys, strconv.Itoa(a.PageNum))}if a.PageSize > 0 {keys = append(keys, strconv.Itoa(a.PageSize))}//ARTICLE_LIST_...return strings.Join(keys, "_")
}

同目录新建 tag.go

// Package cache_service 缓存相关服务,单个或多个tag键名
package cache_serviceimport ("github.com/kingsill/gin-example/pkg/e""strconv""strings"
)// Tag 定义缓存中可能的Tag键名包含的要素
type Tag struct {ID    intName  stringState intPageNum  intPageSize int
}// GetTagsKey 获取全面的Tag键名
func (t *Tag) GetTagsKey() string {keys := []string{e.CACHE_TAG,"LIST",}if t.Name != "" {keys = append(keys, t.Name)}if t.State >= 0 {keys = append(keys, strconv.Itoa(t.State))}if t.PageNum > 0 {keys = append(keys, strconv.Itoa(t.PageNum))}if t.PageSize > 0 {keys = append(keys, strconv.Itoa(t.PageSize))}return strings.Join(keys, "_")
}

Redis 工具包

  1. 下载 redigo 包,帮助使用 redis
go get github.com/gomodule/redigo@latest
  1. 打开 pkg 目录,新建 gredis/redis.go,写入内容:
package gredisimport ("encoding/json""github.com/gomodule/redigo/redis""github.com/kingsill/gin-example/pkg/setting""time"
)// RedisConn 定义全局变量RedisConn为redis连接池
var RedisConn *redis.Pool// Setup 初始化redis服务
func Setup() error {//实例化RedisConn,从setting中加载定义的配置信息RedisConn = &redis.Pool{MaxIdle:     setting.RedisSetting.MaxIdle,MaxActive:   setting.RedisSetting.MaxActive,IdleTimeout: setting.RedisSetting.IdleTimeout,Dial: func() (redis.Conn, error) { //创建并配置一个连接c, err := redis.Dial("tcp", setting.RedisSetting.Host)if err != nil {return nil, err}if setting.RedisSetting.Password != "" {if _, err := c.Do("AUTH", setting.RedisSetting.Password); err != nil {c.Close()return nil, err}}return c, err},TestOnBorrow: func(c redis.Conn, t time.Time) error { //测试连接_, err := c.Do("PING")return err},}return nil
}// Set redis存储的key-value,添加数据
func Set(key string, data interface{}, time int) error {conn := RedisConn.Get()defer conn.Close()//将data以json编码为valuevalue, err := json.Marshal(data)if err != nil {return err}_, err = conn.Do("SET", key, value)if err != nil {return err}//设置过期时间,单位为s_, err = conn.Do("EXPIRE", key, time)if err != nil {return err}return nil
}// Exists 检查当前redis中是否有当前key
func Exists(key string) bool {conn := RedisConn.Get()defer conn.Close()exists, err := redis.Bool(conn.Do("EXISTS", key))if err != nil {return false}return exists
}// Get 获取要查询的key对应的value
func Get(key string) ([]byte, error) {conn := RedisConn.Get()defer conn.Close()reply, err := redis.Bytes(conn.Do("GET", key))if err != nil {return nil, err}return reply, nil
}// Delete 删除redis中传入的键值对
func Delete(key string) (bool, error) {conn := RedisConn.Get()defer conn.Close()return redis.Bool(conn.Do("DEL", key))
}// LikeDeletes 删除所有包含指定键名的键值对
func LikeDeletes(key string) error {conn := RedisConn.Get()defer conn.Close()keys, err := redis.Strings(conn.Do("KEYS", "*"+key+"*"))if err != nil {return err}for _, key := range keys {_, err = Delete(key)if err != nil {return err}}return nil
}

redis 使用

原来的逻辑中,以检索文件为例,我们直接在 mysql 中检索数据,现在我们在之前新增在 redis 中搜索,如果没有,再跳转到 mysql

并且我们将检索封装成一个函数,代码阅读更加直观
打开 service 目录,新建 article_service/article.go

package article_serviceimport ("encoding/json""github.com/kingsill/gin-example/models""github.com/kingsill/gin-example/pkg/gredis""github.com/kingsill/gin-example/pkg/logging""github.com/kingsill/gin-example/service/cache_service"
)// Article 建立文章结构体,方便信息存储及与gorm的互动
type Article struct {ID            intTagID         intTitle         stringDesc          stringContent       stringCoverImageUrl stringState         intCreatedBy     stringModifiedBy    stringPageNum  intPageSize int
}// Add 新建文章服务
func (a *Article) Add() error {//创建article实例article := map[string]interface{}{"tag_id":          a.TagID,"title":           a.Title,"desc":            a.Desc,"content":         a.Content,"created_by":      a.CreatedBy,"cover_image_url": a.CoverImageUrl,"state":           a.State,}if err := models.AddArticle(article); err != nil {return err}return nil
}// Edit 编辑文章服务
func (a *Article) Edit() error {return models.EditArticle(a.ID, map[string]interface{}{"tag_id":          a.TagID,"title":           a.Title,"desc":            a.Desc,"content":         a.Content,"cover_image_url": a.CoverImageUrl,"state":           a.State,"modified_by":     a.ModifiedBy,})
}// Get 查询文章服务
func (a *Article) Get() (*models.Article, error) {var cacheArticle *models.Article//推算文章键名cache := cache_service.Article{ID: a.ID}key := cache.GetArticleKey()//根据文章键名在redis中查询if gredis.Exists(key) {data, err := gredis.Get(key)if err != nil {logging.Info(err)} else {json.Unmarshal(data, &cacheArticle)return cacheArticle, nil}}//redis中没有查询到则在mysql中查询article, err := models.GetArticle(a.ID)if err != nil {return nil, err}//在redis中存储该组键值对,并设置过期时间gredis.Set(key, article, 3600)return article, nil
}// GetAll 类比上面 get 进行理解
func (a *Article) GetAll() ([]*models.Article, error) {var (articles, cacheArticles []*models.Article)cache := cache_service.Article{TagID: a.TagID,State: a.State,PageNum:  a.PageNum,PageSize: a.PageSize,}key := cache.GetArticlesKey()if gredis.Exists(key) {data, err := gredis.Get(key)if err != nil {logging.Info(err)} else {json.Unmarshal(data, &cacheArticles)return cacheArticles, nil}}articles, err := models.GetArticles(a.PageNum, a.PageSize, a.getMaps())if err != nil {return nil, err}gredis.Set(key, articles, 3600)return articles, nil
}// Delete 简单对之前函数的包装调用
func (a *Article) Delete() error {return models.DeleteArticle(a.ID)
}func (a *Article) ExistByID() (bool, error) {return models.ExistArticleByID(a.ID)
}func (a *Article) Count() (int, error) {return models.GetArticleTotal(a.getMaps())
}// 构建适用于多个文章查询等的条件映射
func (a *Article) getMaps() map[string]interface{} {maps := make(map[string]interface{})maps["deleted_on"] = 0if a.State != -1 {maps["state"] = a.State}if a.TagID != -1 {maps["tag_id"] = a.TagID}return maps
}

过程中可能会对之前的函数进行一定小小的修改,根据报错进行修改即可

同样的,大家可以自行建立tag_service/tag.go

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/790536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch 压测实践总结

背景 搜索、ES运维场景离不开压力测试。 1.宿主机层面变更:参数调优 & 配置调整 & 硬件升级2.集群层面变更:参数调优3.索引层面变更:mapping调整 当然还有使用层面变更,使用API调优(不属于该文章的讨论范围…

四川古力未来科技抖音小店:安全便捷,购物新体验

在数字化浪潮席卷全球的今天,电商平台的安全性与便捷性成为了消费者最为关心的问题。四川古力未来科技有限公司,凭借其强大的技术实力和深厚的行业经验,为广大消费者带来了一个安全可靠的购物新选择——古力未来科技抖音小店。 古力未来科技抖…

Twitter Api查询用户粉丝列表

如果大家为了获取实现方式代码的话可能要让大家失望了,这边文章主要是为了节省大家开发时间,少点坑。https://api.twitter.com/2/users/:id/followers ,这个接口很熟悉吧,他是推特提供的获取用户关注者(粉丝&#xff0…

基于AI智能识别技术的智慧展览馆视频监管方案设计

一、建设背景 随着科技的不断进步和社会安全需求的日益增长,展览馆作为展示文化、艺术和科技成果的重要场所,其安全监控系统的智能化升级已成为当务之急。为此,旭帆科技(TSINGSEE青犀)基于视频智能分析技术推出了展览…

前端Vue Node.js + Express + MongoDB 构建的后端服务API接口

构建一个使用 Vue.js 作为前端,Node.js + Express + MongoDB 作为后端服务的全栈应用涉及到多个步骤。这里简要概述整个过程,并提供一些基本的代码示例来帮助你开始。 步骤 1: 设置 MongoDB 数据库 安装 MongoDB: 根据你的操作系统从 MongoDB 官网 下载并安装 MongoDB。启动…

sql之日期函数

日期函数 CURDATE()/CURRENT_DATE()返回当前日期 select CURRENT_DATE(),CURDATE();CURRENT_TIME()/CURTIME()返回当前时间 -- 没有日期 select CURRENT_TIME(),CURTIME();CURRENT_TIMESTAMP()返回当前日期和时间 select DATE_FORMAT(CURRENT_TIMESTAMP(),%Y年%m月%d日 %H时…

再拓信创生态圈|宁盾身份域管与深信服桌面云完成兼容互认证

近日,宁盾国产化身份域管(即身份目录服务软件)与深信服桌面云系统aDesk完成产品兼容性互认证。经过共同严格测试,宁盾国产化身份域管能够与深信服桌面云系统兼容对接运行,双方相互兼容,共同为企事业单位提供…

torch.linspace()、tensor.item()及tensor.tolist()方法使用

PyTorch中的torch.linspace torch.linspace(start, end, steps100, outNone, dtypeNone,layouttorch.strided, deviceNone, requires_gradFalse) start: 开始值 end:结束值 steps:分割的点数,默认为100 import torchdrop_path_…

H5面临的网络安全威胁和防范措施

H5,是基于HTML5技术的网页文件。HTML,全称Hyper Text Markup Language,即超文本标记语言,由Web的发明者Tim Berners-Lee与同事Daniel W. Connolly共同创立。作为SGML的一种应用,HTML编写的超文本文档能够独立于各种操作…

tomcat-连接器架构设计

一、NioEndpoint组件 Tomcat的NioEndPoint组件实现了I/O多路复用模型,接下来我会介绍NioEndpoint的实现原理。 1.总体工作流程 我们知道,对于Java的多路复用器的使用,无非是两步: 1.创建一个Seletor,在它身上注册各…

Cloud flare反向代理流量实验

前言 本实验将会为大家解析cloud flare的反向解析代理服务如何搭建,works如何创建等等。本文中教学创建的实例已在文章编写结束后释放,该项技术不可用于违法用途!违者自行承担后果!! 原理拓扑图 一、知识链条 1、Clou…

【深度学习|Pytorch】torchvision.datasets.ImageFolder详解

ImageFolder详解 1、数据准备2、ImageFolder类的定义transforms.ToTensor()解析 3、ImageFolder返回对象 1、数据准备 创建一个文件夹,比如叫dataset,将cat和dog文件夹都放在dataset文件夹路径下: 2、ImageFolder类的定义 class ImageFol…

目标跟踪——行人车辆数据集

一、重要性及意义 首先,目标跟踪对于个人和组织的目标实现至关重要。无论是个人职业发展、企业业务增长还是政府的社会发展,目标跟踪都能够帮助我们明确目标,并将其分解为可行的步骤和时间表。这有助于我们保持动力和专注,提高效…

【开源产品部署系列】一、RuoYi-Radius搭建流程

系列文章目录 【开源产品部署系列】一、RuoYi-Radius搭建流程 文章目录 系列文章目录[TOC](文章目录) 前言一、RuoYi-Radius简介二、部署过程2.1、Centos8 环境准备2.2、启动虚拟机2.3、freeradius 安装2.4、freeradius 配置2.4.1、通过软连接方式启动rest模块2.4.2、修改配置…

数据质量决定大模型能力,景联文科技提供高质量大模型数据

随着大模型的深入发展,各类资源要素的配置状态已悄然变化。其中,数据的价值已被提升到一个新高度。 大模型往往拥有庞大的参数和复杂的网络结构,需要大量的数据来学习和优化。数据的质量和数量直接决定了模型的训练效果。若数据不足或质量不佳…

过拟合(Overfitting)

过拟合(Overfitting)是机器学习中的一个重要概念,它指的是模型在训练数据上表现得过于优秀,以至于在训练集上达到了很高的准确率,但在未见过的数据(测试集或实际应用中的数据)上表现却大幅下降的…

Vue-Router 的懒加载如何实现

非懒加载: import List from /components/list.vue const router new VueRouter({routes: [{ path: /list, component: List }] }) (1)方案一(常用):使用箭头函数import动态加载 const List () > import(/components/list…

SpringBoot如何集成nacos,用于服务发现和配置管理

1.创建srpingBoot的工程 2.pom文件如下&#xff0c;如果出现无法正确读取nacos的配置&#xff0c;很大程度是因为jar包的版本问题导致&#xff0c;当前我使用的是 springBoot的版本&#xff1a; <parent><groupId>org.springframework.boot</groupId><…

MySQL-视图:视图概述、创建、查看、更新、修改、删除

第14章 视图 1. 常见的数据库对象2. 视图概述2.1 为什么使用视图&#xff1f;2.2 视图的理解 3. 创建视图3.1 创建单表视图3.2 创建多表联合视图3.3 基于视图创建视图 4. 查看视图5. 更新视图的数据5.1 一般情况5.2 不可更新的视图 6. 修改、删除视图6.1 修改视图6.2 删除视图 …

详解网络攻击的发生原因、类型及如何防范

网络攻击是访问计算机系统或者大小&#xff0c;修改或窃取数据的未经授权的企图。网络破坏分子可以使用多种攻击媒介&#xff0c;推出包括网络攻击的恶意软件&#xff0c;网络钓鱼&#xff0c;勒索&#xff0c;以及人在这方面的中间人攻击。固有风险和残余风险使这些攻击中的每…