[golang gin框架] 24.Gin 商城项目-redis讲解以及操作

news/2024/4/24 15:54:47/

一.reids相关文章

Redis五种数据类型及其应用场景

REDIS中的缓存穿透,缓存击穿,缓存雪崩原因以及解决方案

redis实现用户签到,统计活跃用户,用户在线状态,用户留存率

[golang gin框架] 12.Gin 商城项目-base64Captcha生成图形验证码以及分布式架构中配置Captcha

[go学习笔记.第十七章.redis的使用] 1.redis的使用

linux下yum安装redis服务

二.golang中使用redis

redis介绍以及安装见: [go学习笔记.第十七章.redis的使用] 1.redis的使用
在这里使用go-redis插件来对接redis
模块: https://github.com/go-redis/redis
文档: https://redis.uptrace.dev/
安装go-redis:
下载go-redis,在main.go目录下,执行: go get github.com/redis/go-redis/v9,然后:
import (
"github.com/redis/go-redis/v9"
)
就可以使用go-redis了
下面看看redis相关代码:

1.redisCore.go

该文件中是 连接redis数据库核心代码
package models//redis官网: github.com/go-redis
//下载go-redis: go get github.com/redis/go-redis/v9
//连接redis数据库核心代码import ("context""github.com/redis/go-redis/v9"
)//Go1.7 加入了一个新的标准库 context,它定义了 Context 类型,专门用来简化 对于处理
单个请求的多个 goroutine 之间与请求域的数据、取消信号、截止时间等相关操作
var ctx = context.Background()
//全局使用,就需要把定义成公有的
var ctxRedis = context.Background()var (RedisDb *redis.Client
)//自动初始化数据库
func init() {RedisDb = redis.NewClient(&redis.Options{Addr:     "127.0.0.1:6379",Password: "", // no password setDB:       0,  // use default DB})//连接redis_, err := RedisDb.Ping(ctxRedis).Result()//判断连接是否成功if err != nil {println(err)}
}

2.redisOper.go

操作redis案例说明
package modelsimport ("context""fmt""time"
)var ctx = context.Background()type RedisOper struct {
}//RedisDb调用上面代码中的RedisDb//操作字符串:Set
func (r RedisOper) Set(key string, value string) error {err := RedisDb.Set(ctx, key, value, 0).Err()return err
}//操作字符串:Get
func (r RedisOper) Get(key string) string {val, err := RedisDb.Get(ctx, key).Result()if err != nil {fmt.Println(err)return ""}return val
}//操作列表(list)
func (r RedisOper) ListOper() {RedisDb.LPush(ctx, "hobby", "吃饭")RedisDb.LPush(ctx, "hobby", "睡觉")RedisDb.RPush(ctx, "hobby", "写代码")hobby, _ := RedisDb.LRange(ctx, "hobby", 0, -1).Result()fmt.Println(hobby)
}//操作集合(set)
func (r RedisOper) SetOper() {RedisDb.SAdd(ctx, "hobby", "吃饭", "睡觉", "吃饭")RedisDb.SAdd(ctx, "hobby", "写代码")hobby, _ := RedisDb.SMembers(ctx, "hobby").Result()fmt.Println(hobby)
}//操作哈希(hash)
func (r RedisOper) SetOper() {err := RedisDb.HMSet(ctx, "userinfo", map[string]interface{}{"username": "张三","age":      "20",}).Err()if err != nil {fmt.Println(err)}userinfo, _ := RedisDb.HGetAll(ctx, "userinfo").Result()fmt.Println(userinfo)fmt.Println(userinfo["username"])
}//设置过期时间
func (r RedisOper) SetExpire() {RedisDb.Set(ctx, "age", 20, time.Second*10)RedisDb.LPush(ctx, "hobby", "吃饭")RedisDb.Expire(ctx, "hobby", time.Second*10)
}//删除数据
func (r RedisOper) Del() {RedisDb.Set(ctx, "age", 20, 0)RedisDb.Del(ctx, "age")RedisDb.LPush(ctx, "hobby", "吃饭")RedisDb.FlushAll(ctx)
}

3.Redis 分布式架构订阅发布

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1
之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

案例演示:

redis_pub.go是一个发布的频道端,发布消息,redis_sub1.go,redis_sub2.go,redis_sub3.go是三个客户端,订阅redis_pub.go这个频道端对应频道发布的消息,当频道端发布消息时,三个订阅的客户端会各自订阅频道收到的消息.代码如下:

redis_pub.go

package mainimport ("context""fmt""github.com/go-redis/redis/v9"
)var ctx = context.Background()func main() {//连接redis数据库rdb := redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", // no password setDB:       0,  // use default DB})_, err := rdb.Ping(ctx).Result()if err != nil {fmt.Println("redis数据库连接失败")} else {fmt.Println("redis数据库连接成功...")}//发布消息:rdb.Publish(ctx, "ch", "我是ch的数据...")rdb.Publish(ctx, "ch2", "我是ch2的数据...")
}
假如redis_sub1.go订阅了ch这个频道,redis_sub2.go,redis_sub3.go订阅了ch,ch2这两个频道,对应的代码如下:

redis_sub1.go

package mainimport ("context""fmt""github.com/go-redis/redis/v9"
)var ctx = context.Background()func main() {//连接redis数据库rdb := redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", // no password setDB:       0,  // use default DB})_, err := rdb.Ping(ctx).Result()if err != nil {fmt.Println("redis数据库连接失败")} else {fmt.Println("redis数据库连接成功...")}//订阅消息pubsub := rdb.Subscribe(ctx, "ch")ch := pubsub.Channel()for msg := range ch {fmt.Println(msg.Channel, msg.Payload)}
}

redis_sub2.go,redis_sub3.go

package mainimport ("context""fmt""github.com/go-redis/redis/v9"
)var ctx = context.Background()func main() {//连接redis数据库rdb := redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", // no password setDB:       0,  // use default DB})_, err := rdb.Ping(ctx).Result()if err != nil {fmt.Println("redis数据库连接失败")} else {fmt.Println("redis数据库连接成功...")}//订阅消息pubsub := rdb.Subscribe(ctx, "ch")ch := pubsub.Channel()for msg := range ch {fmt.Println(msg.Channel, msg.Payload)}//订阅消息pubsub2 := rdb.Subscribe(ctx, "ch2")ch2 := pubsub2.Channel()for msg2 := range ch2 {fmt.Println(ms2g.Channel, msg2.Payload)}
}

三.项目中使用redis

  1. 修改redisCore.go核心代码

(1).redis配置修改

把redis配置放入conf/app.ini下,app.ini增加如下代码:
[redis]
ip          = localhost
port        = 6379
database    = 1
redisEnable = true

(2).完善redisCore.go

package models//redis官网: github.com/go-redis
//下载go-redis: go get github.com/redis/go-redis/v9
//连接redis数据库核心代码import ("context""fmt""github.com/redis/go-redis/v9""gopkg.in/ini.v1""os"
)//全局使用,就需要把定义成公有的
var ctxRedis = context.Background()var (RedisDb *redis.Client
)//是否开启redis
var redisEnable bool//自动初始化数据库
func init() {//加载配置文件config, iniErr := ini.Load("./conf/app.ini")if iniErr != nil {fmt.Printf("Fail to read file: %v", iniErr)os.Exit(1)}//获取redis配置ip := config.Section("redis").Key("ip").String()port := config.Section("redis").Key("port").String()redisEnable, _ = config.Section("redis").Key("redisEnable").Bool()//判断是否开启redisif redisEnable {RedisDb = redis.NewClient(&redis.Options{Addr:     ip + ":" + port,Password: "", // no password setDB:       0,  // use default DB})//连接redis_, err := RedisDb.Ping(ctxRedis).Result()//判断连接是否成功if err != nil {println(err)}}
}

2.创建redisCache.go

里面重构Set,Get方法
package modelsimport ("encoding/json""time"
)type RedisCache struct {
}//设置
func (r RedisCache) Set(key string, value interface{}, expiration int) {if redisEnable {  //判断是否开启redisv, err := json.Marshal(value)  //value是一个空接口类型,里面可以是字符串,切片,结构体,所以转成json保存if err == nil {//RedisDb:调用redisCore.go中的RedisDbRedisDb.Set(ctxRedis, key, string(v), time.Second*time.Duration(expiration))}}
}//获取
func (r RedisCache) Get(key string, obj interface{}) bool {if redisEnable { //判断是否开启redisvalueStr, err1 := RedisDb.Get(ctxRedis, key).Result()if err1 == nil && valueStr != "" {err2 := json.Unmarshal([]byte(valueStr), obj)return err2 == nil}}return false
}

3.商品首页控制器IndexController.go使用redis

package frontend//首页import ("github.com/gin-gonic/gin""gorm.io/gorm""goshop/models""net/http""strings"
)type IndexController struct {
}func (con IndexController) Index(c *gin.Context) {//实例化redisCache结构体redisCache := models.RedisCache{}//获取顶部导航列表topNavList := []models.Nav{}//判断redis中是否存在数据if hasTopNavList := redisCache.Get("topNavList", &topNavList); !hasTopNavList {  //不存在数据,则从数据中获取数据,并把数据保存到redismodels.DB.Where("status = 1 AND position = 1").Find(&topNavList)redisCache.Set("topNavList", topNavList, 3600)}//获取网站轮播图数据focusList := []models.Focus{}if hasFocusList := redisCache.Get("focusList", &focusList); !hasFocusList {models.DB.Where("status = 1 AND focus_type = 1").Find(&focusList)redisCache.Set("focusList", focusList, 3600)}//获取分类数据goodsCateList := []models.GoodsCate{}if hasGoodsCateList := redisCache.Get("goodsCateList", &goodsCateList); !hasGoodsCateList {//获取分类列表以及下级分类,并进行排序models.DB.Where("pid = ? AND status = ?", 0, 1).Order("sort DESC").Preload("GoodsCateItems", func(db *gorm.DB) *gorm.DB {return db.Where("goods_cate.status = 1").Order("goods_cate.sort DESC")} ).Find(&goodsCateList)redisCache.Set("goodsCateList", goodsCateList, 3600)}//获取中间导航middleNavList := []models.Nav{}if hasMiddleNavList := redisCache.Get("middleNavList", &middleNavList); !hasMiddleNavList {models.DB.Where("status = ? AND position = ? ", 1, 2).Find(&middleNavList)redisCache.Set("middleNavList", middleNavList, 3600)//循环,获取中间导航对应的商品数据for i:= 0; i < len(middleNavList);i++{//获取管理商品//替换字符串中的中文逗号strings.ReplaceAll()relation := strings.ReplaceAll(middleNavList[i].Relation, ",", ",")//把字符串转换成切片relationIds := strings.Split(relation, ",")//获取对应的商品信息goodsList := []models.Goods{}models.DB.Where("status = ?", 1).Where("id in ?", relationIds).Select("id, title, goods_img, price").Find(&goodsList)middleNavList[i].GoodsItems = goodsList}}//获取手机分类下面的商品phoneList := []models.Goods{}if hasPhoneList := redisCache.Get("phoneList", &phoneList); !hasPhoneList {phoneList := models.GetGoodsByCategory(23, "best", 10)redisCache.Set("phoneList", phoneList, 3600)}c.HTML(http.StatusOK, "frontend/index/index.html", gin.H{"topNavList": topNavList,"focusList": focusList,"goodsCateList": goodsCateList,"middleNavList": middleNavList,"phoneList": phoneList,})
}

[上一节][golang gin框架] 23.Gin 商城项目-前台templates模板分离,首页,顶部导航,轮播图 左侧分类数据渲染

[下一节][golang gin框架] 25.Gin 商城项目-配置清除缓存以及前台列表页面数据渲染公共数据


http://www.ppmy.cn/news/46606.html

相关文章

linux程序设置开机自动启动/etc/rc.d/rc.local, /etc/profile.d/

Linux 下设置开机启动的几种方法 1 修改 /etc/rc.d/rc.local 文件 把自启动脚本放在/etc/profile.d/下 为了保证一定能执行&#xff0c;最好再加个赋权操作 chmod x /etc/profile.d/test01.sh (test.sh为自己的脚本) 特点&#xff1a;在用MobaXterm等远程访问服务器的工具&a…

一个大二学生送给大一学弟学妹的建议

博主简介&#xff1a;先简单的介绍一下我吧&#xff0c;本人是一名大二学生&#xff0c;来自四川。目前所学专业是人工智能&#xff0c;致力于在CSDN平台分享自己的学习内容。 我为什么要写这篇文章&#xff1f; 我来到CSDN也已经一年了&#xff0c;在这一年里面&#xff0c;我…

【从零开始学Skynet】实战篇《球球大作战》(十):agent代码设计

现在开发登录流程涉及的最后一个服务agent&#xff0c;完成后就可以真正地把框架运行起来了。还会演示agent的单机功能&#xff0c;做个“打工”小游戏。 1、消息分发 玩家登录后&#xff0c;gateway会将客户端协议转发给agent&#xff08;流程图的阶段⑨&#xff09;。 新建se…

Hive表操作

插入数据sql、导出数据sql 1.insert 语法格式为&#xff1a; 基本的插入语法&#xff1a; INSERT OVERWRITE TABLE tablename [PARTITON(partcol1val1,partclo2val2)]select_statement FROM from_statementinsert overwrite table test_insert select * from test_…

4.34、组播(多播)

4.34、多播 1.组播(多播)的介绍①组播地址②如何设置组播&#xff08;组播的使用&#xff09; 2.代码编写①服务端②客户端 1.组播(多播)的介绍 单播地址标识单个 IP 接口&#xff0c;广播地址标识某个子网的所有 IP 接口&#xff0c;多播地址标识一组 IP 接口。单播和广播是寻…

Java每日一练(20230416)

目录 1. 三数之和 &#x1f31f;&#x1f31f; 2. 基本计算器 &#x1f31f;&#x1f31f;&#x1f31f; 3. 通配符匹配 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java…

ubuntu输入法问题汇总

Xfce4桌面环境输入法 Ubuntu20.04、ubuntu21.04中安装xfce4桌面环境&#xff0c;自带中文输入法&#xff1b; 原生xubuntu20.04中文输入法问题解决办法&#xff1a; 更新语言支持失败的话&#xff0c;终端键入&#xff1a;sudo apt-get install cmake qt5-default qtcreator…

在Github中77k星的王炸AutoGPT,会独立思考,直接释放双手

文章目录 1 前言1.1 什么是AutoGPT1.2 为什么是AutoGPT 2 AutoGPT部分实例2.1 类似一个Workflow2.2 市场调研2.3 自己写播客2.4 接入客服 3 安装和使用AutoGPT3.1 安装3.2 基础用法3.3 配置OpenAI的API3.4 配置谷歌API3.5 配置Pinecone API 4.讨论 1 前言 迄今为止&#xff0c…

Java基本类型和包装类型int和Integer

Java基本类型和包装类型int和Integer 基本类型和包装类型的区别使用中的问题 基本类型和包装类型的区别 Java中的数据类型可以分为两种&#xff1a;基本类型&#xff08;Primitive Type&#xff09;和包装类型&#xff08;Wrapper Class&#xff09;。这两者之间也有几个区别&…

【UE4】关卡流送的demo

关卡流送功能可以将地图文件加载到内存中&#xff0c;或者从内存中卸载&#xff0c;并在游戏过程中切换地图的可视性。 这样一来&#xff0c;场景便能拆分为较小的地图块&#xff0c;并且只有相关部分才会占用资源并被渲染。 正确设置后&#xff0c;开发者便能创建大型、无缝衔…

面试题:Ajax、Fetch、Axios三者的区别

Ajax 它的全称是&#xff1a;Asynchronous JavaScript And XML&#xff0c;翻译过来就是“异步的 Javascript 和 XML”。 Ajax 是一个技术统称&#xff0c;是一个概念模型&#xff0c;它囊括了很多技术&#xff0c;并不特指某一技术&#xff0c; Ajax 是一种思想&#xff0c;X…

java的泛型

1. 泛型是什么 ​ Java泛型是J2 SE1.5中引入的一个新特性&#xff0c;其本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数&#xff08;type parameter&#xff09;, 这种参数类型可以用在类、接口和方法的创建中&#xff0c;分别称为泛型类、泛型接口、…

Dell Inspiron 5570电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板Dell Inspiron 5570 处理器Intel(R) Core(TM) i7-8550U CPU 1.80GHz已驱动 内存8 GB 2400 MHz DDR4已驱动 硬盘samsung ssd 850 evo 250 go已驱…

数据结构——排序

排序 一、排序的概念二、直接插入排序希尔排序 三、直接选择排序四、堆排序1、堆的概念2、堆排序 五、冒泡排序六、快速排序七、归并排序八、基数排序排序算法的时间复杂度和空间复杂度 一、排序的概念 课本概念&#xff08;P165&#xff09; (1&#xff09;内部排序。内部排…

实现3D动画

一、transform Transform是形变的意思&#xff08;通常也叫变换&#xff09;&#xff0c;transformer就是变形金刚 常见的函数transform function有&#xff1a; 平移&#xff1a;translate(x, y) 缩放&#xff1a;scale(x, y) 旋转&#xff1a;rotate(deg) 倾斜&#xff1a;sk…

TensorFlow 和 Keras 应用开发入门:1~4 全

原文&#xff1a;Beginning Application Development with TensorFlow and Keras 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形…

移动端树形结构

该组件依据需求来做&#xff0c;当前包含三种选择状态&#xff0c;选中&#xff0c;未选中&#xff0c;半选。由于不需要做树形的收缩展开故没有写相关内容。树形展开与收缩与选中类似&#xff0c;只需要在节点上挂载相关字段即可实现。由于需求需要增加不限的功能&#xff0c;…

Java基础 泛型

问题1. B继承A 为什么 List<B> 不能赋值给List<A> 假设有如下代码 class A{} class B extends A{}List<B> b new ArrayList<>(); List<A> a b; // 编译报错List<A> List<B> 在运行时泛型被抹除&#xff0c; 都是List类型&#…

Git使用

1、git bash here 2、git init 初始化; 2.1、配置信息 git config --global user.email "421018843qq.com" git config --global user.name "pql" 3、git status 检测当前目录下文件的状态 三种颜色状态&#xff1a; 红色&#xff1a;…

【通过Cpython3.9源码看看python中的大小整数】

小整数 /* interpreter state */#define _PY_NSMALLPOSINTS 257 #define _PY_NSMALLNEGINTS 5这是CPython中定义的两个常量&#xff0c;它们用于控制解释器状态中的小整数对象池。在CPython中&#xff0c;小整数对象池是一种优化机制&#xff0c;用于减少…