Go从入门到精通(24)
一个简单web项目-添加redis缓存
文章目录
前言
在 Go 语言中使用 Redis 缓存频繁访问的数据,可以显著提升应用性能。
缓存流程说明
查询流程
- Cache Hit → 直接返回缓存数据
- Cache Miss → 查询数据库 → 写入缓存 → 返回数据
更新流程
- 更新数据库 → 删除缓存(而非更新)→ 下次查询时自动刷新
缓存策略
- 使用 JSON 序列化存储对象
- 设置 5 分钟过期时间(根据业务需求调整)
- 采用Read-Through和Write-Invalidate策略
优势
- 减少数据库压力(高频访问的数据仅第一次查询 DB)
- 提升响应速度(Redis 读取延迟通常 < 1ms)
- 支持分布式缓存(多实例共享同一 Redis)
redis使用
安装依赖
go get github.com/go-redis/redis/v8
配置 Redis 连接
// cache/redis.go
package cache
import (
"context"
"fmt"
"log"
"os"
"strconv"
"strings"
"time"
"github.com/go-redis/redis/v8"
)
var RedisClient redis.UniversalClient
var Ctx = context.Background()
func InitRedis() {
// 从环境变量获取 Redis 配置
mode := os.Getenv("REDIS_MODE")
if mode == "" {
mode = "single" // 默认单节点模式
}
switch mode {
case "cluster":
// 集群模式
addresses := os.Getenv("REDIS_CLUSTER_ADDRESSES")
if addresses == "" {
log.Fatal("REDIS_CLUSTER_ADDRESSES 环境变量未设置")
}
password := os.Getenv("REDIS_PASSWORD")
RedisClient = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: strings.Split(addresses, ","),
Password: password,
// 其他可选配置
MaxRetries: 3,
MinRetryBackoff: 8 * time.Millisecond,
MaxRetryBackoff: 512 * time.Millisecond,
DialTimeout: 5 * time.Second,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
PoolSize: 100,
MinIdleConns: 20,
})
default:
// 单节点模式
host := os.Getenv("REDIS_HOST")
if host == "" {
host = "localhost"
}
port := os.Getenv("REDIS_PORT")
if port == "" {
port = "6379"
}
password := os.Getenv("REDIS_PASSWORD")
db, _ := strconv.Atoi(os.Getenv("REDIS_DB"))
RedisClient = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%s", host, port),
Password: password,
DB: db,
// 其他可选配置
MaxRetries: 3,
MinRetryBackoff: 8 * time.Millisecond,
MaxRetryBackoff: 512 * time.Millisecond,
DialTimeout: 5 * time.Second,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
PoolSize: 100,
MinIdleConns: 20,
})
}
// 测试连接
if mode == "cluster" {
_, err := RedisClient.Ping(Ctx).Result()
if err != nil {
log.Fatalf("无法连接到 Redis Cluster: %v", err)
}
log.Println("Redis Cluster 连接成功")
} else {
_, err := RedisClient.Ping(Ctx).Result()
if err != nil {
log.Fatalf("无法连接到 Redis: %v", err)
}
log.Println("Redis 单节点连接成功")
}
}
修改用户处理函数添加缓存
func GetCurrentUserHandler(c *gin.Context) {
userID := c.MustGet("user_id").(string)
// 1. 先从 Redis 缓存中获取
cacheKey := fmt.Sprintf("user:%s", userID)
userJSON, err := cache.RedisClient.Get(cache.Ctx, cacheKey).Result()
if err == nil {
// 缓存命中
var user models.User
if err := json.Unmarshal([]byte(userJSON), &user); err == nil {
c.JSON(http.StatusOK, user)
return
}
}
// 2. 缓存未命中,从数据库获取
user, exists := users[userID]
if !exists {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
// 不返回密码
user.Password = ""
// 3. 将数据存入 Redis 缓存(设置 5 分钟过期)
userByteArray, err := json.Marshal(user)
if err == nil {
userJSON = string(userByteArray)
cache.RedisClient.Set(cache.Ctx, cacheKey, userJSON, 5*time.Minute)
}
c.JSON(http.StatusOK, user)
}
//其他方法类似
修改主函数初始化 Redis
cache.InitRedis()
配置环境变量
# 单节点模式配置
REDIS_MODE=single
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
# 集群模式配置(覆盖单节点配置)
# REDIS_MODE=cluster
# REDIS_CLUSTER_ADDRESSES=192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379
# REDIS_PASSWORD=