今天来简单写一点我在做大项目是如何使用redis的
需求:
- 点赞、取消赞操作十分频繁导致视频获赞总数获取、修改频繁
- 视频id参数校验,判断是否存在此视频(前端防君子不防帅哥)
个人觉得这里应该往redis存入点赞关系,以满足判断是否点赞和未点赞需求,由于笔者项目经验有限,也是第一次使用redis,有很多理解不对和写的不好的地方
实现步骤
- 首先肯定是创建redis客户端
- 定义存入redis的数据格式并从mysql数据库中获取数据
- 封装从redis获取数据的函数
- 使用go语言的定时任务定时持久化redis中数据到mysql中
代码实现
- 初始化连接和创建redis客户端(以及mysql)
package global import ( ) var ( DB *gorm.DB RS *redis.Client ) func init() { //mysql的连接 网上很多 //redis的连接 网上很多 - 定义存入redis的数据格式并从mysql数据库中获取数据(初始化redis)
var videos []Video global.DB.Find(&videos) // 遍历数据库中的视频数据 for _, video := range videos { key := VideoRedisPrefix + fmt.Sprintf("%d", video.VideoID) // 准备要存储在 Redis 中的数据 data := map[string]interface{}{ "favorite": strconv.FormatInt(video.FavoriteCount, 10), // 将点赞数转为字符串 "comment": strconv.FormatInt(video.CommentCount, 10), // 将评论数转为字符串 "liked": "false", // 初始化点赞状态为 false "commented": "false", // 初始化评论状态为 false } // 使用 Hash Map (HMSet) 存储数据到 Redis client.HMSet(key, data) }
- 解析:
- 查询数据库中的视频数据并存储到
videos切片中。 - 遍历视频数据,为每个视频生成一个唯一的 Redis 键。
- 为每个视频生成要存储在 Redis 中的数据,包括点赞数、评论数,以及初始点赞和评论状态。
- 使用 Redis 客户端的
HMSet方法将生成的数据存储到 Redis 中的 Hash Map 数据结构中 - 封装从redis获取数据的函数
// LikeVideo 方法2:点赞操作
func LikeVideo(videoID int64) error {
key := VideoRedisPrefix + fmt.Sprintf("%d", videoID)
// 更新点赞状态
_, err := client.HSet(key, "liked", "true").Result()
if err != nil {
if err != nil {
//如果redis没有则从数据获取并初始化这条视频
_, _, err = GetVideoFavoriteAndCommentCount(videoID)
if err != nil {
return err
}
}
}
// 增加点赞数
newCount, err := client.HIncrBy(key, "favorite", 1).Result()
if err != nil {
return err
}
fmt.Printf("Liked video %d. New favorite count: %d\n", videoID, newCount)
return nil
}
// UnlikeVideo 方法3:取消点赞操作
func UnlikeVideo(videoID int64) error {
key := VideoRedisPrefix + fmt.Sprintf("%d", videoID)
// 更新点赞状态
_, err := client.HSet(key, "liked", "true").Result()
if err != nil {
return err
}
// 减少点赞数
newCount, err := client.HIncrBy(key, "favorite", -1).Result()
if err != nil {
return err
}
fmt.Printf("Unliked video %d. New favorite count: %d\n", videoID, newCount)
return nil
}
// AddComment 方法4:评论数+1操作
func AddComment(videoID int64) error {
key := VideoRedisPrefix + fmt.Sprintf("%d", videoID)
// 更新评论状态
_, err := client.HSet(key, "commented", "true").Result()
if err != nil {
return err
}
// 增加评论数
newCount, err := client.HIncrBy(key, "comment", 1).Result()
if err != nil {
return err
}
fmt.Printf("Added comment to video %d. New comment count: %d\n", videoID, newCount)
return nil
}
func DelComment(videoID int64) error {
key := VideoRedisPrefix + fmt.Sprintf("%d", videoID)
// 更新评论状态
_, err := client.HSet(key, "commented", "true").Result()
if err != nil {
return err
}
// 减少评论数
newCount, err := client.HIncrBy(key, "comment", -1).Result()
if err != nil {
return err
}
zap.S().Error("Unliked video %d. New favorite count: %d\n", videoID, newCount)
return nil
}
- 使用go语言的定时任务定时持久化redis中数据到mysql中
func main() {
// 连接 Redis 客户端
//初始化操作:查询数据库并将数据存入 Redis
util.InitRedisData()
// 定时任务:每隔5秒将 Redis 数据写入 MySQL 数据库
fmt.Println("redis初始化成功,定时任务开始执行")
ticker := time.NewTicker(50 * time.Second)
defer ticker.Stop()
for range ticker.C {
fmt.Println("Writing Redis data to MySQL...")
WriteRedisVideoToMySQL()
fmt.Println("Done.")
}
}
// WriteRedisVideoToMySQL 将 Redis 数据写入 MySQL 数据库
func WriteRedisVideoToMySQL() {
keys, err := client.Keys(VideoRedisPrefix + "*").Result()
if err != nil {
fmt.Println("Error getting keys from Redis:", err)
return
}
for _, key := range keys {
videoIDStr := key[len(VideoRedisPrefix):]
videoID, err := strconv.ParseInt(videoIDStr, 10, 64)
if err != nil {
fmt.Println("Error converting videoID to int:", err)
continue
}
data, err := client.HGetAll(key).Result()
if err != nil {
fmt.Println("Error getting data from Redis:", err)
continue
}
liked := data["liked"]
commented := data["commented"]
// 仅在点赞数或评论数有变化时更新 MySQL 数据库
if liked == "true" || commented == "true" {
// 从 Redis 数据中获取点赞数和评论数,转为 int64 类型
favoriteCount, _ := strconv.ParseInt(data["favorite"], 10, 64)
commentCount, _ := strconv.ParseInt(data["comment"], 10, 64)
fmt.Println(favoriteCount, commentCount, videoID)
updateData := map[string]interface{}{
"favorite_count": favoriteCount,
"comment_count": commentCount,
}
global.DB.Model(&Video{}).Where("video_id = ?", videoID).Updates(updateData)
fmt.Println("更新数据库")
//将状态设置为false
if _, err = client.HSet(key, "liked", "false").Result(); err != nil {
zap.S().Infof("设置点赞状态异常")
}
if _, err := client.HSet(key, "commented", "false").Result(); err != nil {
zap.S().Infof("设置评论状态异常")
}
}
}
}