首先确认自己已经安装了golang的环境
安装go-redis
go get github.com/redis/go-redis/v9
安装redis
然后解压到自己redis文件夹下即可。
初始化go-redis客户端
确保你打开了redis的服务器,本机的直接双击redis-server.exe即可
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // redis地址
Password: "", // no password set
DB: 0, // use default DB
})
// 测试连接
pong, err := rdb.Ping(ctx).Result()
if err != nil {
fmt.Println("无法连接到redis", err)
return
}
fmt.Println("连接成功", pong)
}
初始化redis的配置参数详解
以下是一个具体的配置案例
package main
import (
"context"
"crypto/tls"
"fmt"
"net"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
// 创建一个新的 Redis 客户端配置
options := &redis.Options{
// 网络类型,使用 tcp 连接 或者 unix
Network: "tcp",
// Redis 服务器地址
Addr: "localhost:6379",
// 客户端名称
ClientName: "myRedisClient",
// 自定义 Dialer 函数, 优先于Network和Addr
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
// 这里可以自定义连接逻辑
return net.Dial(network, addr)
},
// 新连接建立时调用的钩子函数
OnConnect: func(ctx context.Context, cn *redis.Conn) error {
fmt.Println("新连接建立")
return nil
},
// 使用的协议版本,默认是 3, 支持2和3
Protocol: 3,
// Redis 6.0 及以上版本的用户名
Username: "",
// Redis 密码
Password: "",
// 凭据提供者 允许在重连接之前更新用户名和密码
CredentialsProvider: func() (string, string) {
return "", ""
},
// 数据库选择
DB: 0,
// 最大重试次数
MaxRetries: 3,
// 最小重试回退时间
MinRetryBackoff: 8 * time.Millisecond,
// 最大重试回退时间
MaxRetryBackoff: 512 * time.Millisecond,
// 连接超时
DialTimeout: 5 * time.Second,
// 读取超时
ReadTimeout: 3 * time.Second,
// 写入超时
WriteTimeout: 3 * time.Second,
// 是否启用上下文超时
ContextTimeoutEnabled: true,
// 连接池类型,FIFO true表示FIFo false表示LIFO
PoolFIFO: true,
// 基础连接数
PoolSize: 10,
// 连接池超时时间
PoolTimeout: 1 * time.Second,
// 最小空闲连接数, 默认是0
MinIdleConns: 2,
// 最大空闲连接数,默认是0
MaxIdleConns: 5,
// 最大活跃连接数
MaxActiveConns: 20,
// 最大连接闲置时间
ConnMaxIdleTime: 30 * time.Minute,
// 最大连接生命周期
ConnMaxLifetime: 1 * time.Hour,
// TLS 配置
TLSConfig: &tls.Config{
InsecureSkipVerify: true, // 允许不验证 TLS 证书
},
// 限制器接口
Limiter: nil, // 可自定义实现限流逻辑
// 连接时禁用 set-lib 禁止设置客户端名称
DisableIndentity: false,
// 为客户端名称添加后缀
IdentitySuffix: "-suffix",
}
// 创建 Redis 客户端
rdb := redis.NewClient(options)
// 使用上下文
ctx := context.Background()
// 测试连接
pong, err := rdb.Ping(ctx).Result()
if err != nil {
fmt.Println("连接 Redis 失败:", err)
return
}
fmt.Println("连接 Redis 成功:", pong) // 预期输出: 连接 Redis 成功: PONG
// 关闭客户端
defer rdb.Close()
}
自定义Dialer函数
- 定制连接超时与重试逻辑
对于高并发业务,可能会遇到 Redis 连接建立缓慢或频繁重试的问题,特别是在跨数据中心的分布式架构下。可以通过自定义 Dialer 实现更加精细的超时控制和重试策略,避免连接失败导致的业务中断。跨云或跨地域连接时可以设置较长的超时时间
// 自定义Dialer函数,设置连接超时
func customDialer(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := &net.Dialer{
Timeout: 10 * time.Second, // 设置连接超时为 10 秒
}
return dialer.DialContext(ctx, network, addr)
}
- 代理与中转服务
在某些企业环境中,外部网络受限,无法直接访问 Redis 服务器,需要通过代理服务器(如 SOCKS5 或 HTTP 代理)来转发请求。通过自定义 Dialer,可以设置代理服务器的连接逻辑,使 Redis 客户端能够通过代理间接访问 Redis 实例。
customDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
// 使用代理服务器进行连接
dialer := &proxy.Dialer{
ProxyAddress: "proxy-server:port",
Timeout: 5 * time.Second,
}
return dialer.Dial(network, addr)
}
- 安全合规与特殊认证
某些企业有严格的合规要求,网络请求必须经过自定义的加密隧道或安全网关。通过 Dialer 可以实现连接时的特殊认证(例如,通过身份验证代理或自定义的隧道技术进行连接),以确保数据安全。
customDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
// 使用自定义的安全隧道协议
tunnelConn, err := createSecureTunnel(ctx, network, addr)
return tunnelConn, err
}
- 连接负载均衡
大型分布式系统中,可能有多个 Redis 节点提供服务,客户端需要根据特定策略(如权重或健康状态)动态选择连接的 Redis 实例。自定义 Dialer 可以实现动态负载均衡逻辑,在不同节点之间进行负载均衡分发请求。
customDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
redisInstances := []string{"redis1:6379", "redis2:6379", "redis3:6379"}
selectedAddr := selectRedisInstance(redisInstances)
return net.Dial(network, selectedAddr)
}
- 调试和诊断
在一些复杂的生产环境中,开发人员可能需要捕获或记录每次 Redis 连接的详细信息(如延迟、错误、网络行为等)以进行调试。我们可以通过自定义 Dialer 捕获每次连接的日志、性能数据,帮助调试网络连接问题。
customDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
start := time.Now()
conn, err := net.Dial(network, addr)
if err != nil {
log.Printf("连接 Redis 失败: %v", err)
} else {
log.Printf("连接 Redis 成功,耗时: %v", time.Since(start))
}
return conn, err
}
自定义OnConnect函数
- 多数据库支持: Redis 支持多个数据库,但默认连接到
0号数据库。如果您有不同的业务逻辑需要使用不同的 Redis 数据库(如使用1号或2号数据库),可以通过自定义OnConnect在每次连接时自动选择目标数据库。 - 客户端监控和追踪: 在一些大型系统中,您可能希望为不同的 Redis 客户端分配唯一的名称,以便在 Redis 服务器上更方便地进行监控和追踪。通过自定义
OnConnect函数,您可以为每个客户端设置特定的名称。 - 安全性需求: 如果您连接的 Redis 服务器需要基于 ACL(访问控制列表)进行身份验证,您可能需要在每次连接时动态传递用户名和密码,并可以使用
OnConnect函数执行身份验证逻辑。 - 连接健康检查: 在某些场景下,您可能需要在每次连接时执行特定的健康检查操作,例如发送一个
PING命令来确保 Redis 实例是可用的。
package main
import (
"context"
"fmt"
"log"
"github.com/redis/go-redis/v9"
)
func main() {
// 创建一个 Redis 客户端
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // Redis 地址
OnConnect: func(ctx context.Context, cn *redis.Conn) error {
// 在这里可以执行一些自定义逻辑
// 例如:选择数据库和设置客户端名称
err := cn.Ping(ctx).Err()
if err != nil {
return fmt.Errorf("failed to ping Redis: %w", err)
}
log.Println("Ping successful")
// 执行 SETNAME 命令
err = cn.ClientSetName(ctx, "my-redis-client").Err()
if err != nil {
return fmt.Errorf("failed to set client name: %w", err)
}
log.Println("Client name set to my-redis-client.")
return nil
},
// 可以根据需求自定义其他选项
Password: "", // 设置密码
})
// 尝试与 Redis 建立连接并执行 Ping
ctx := context.Background()
if err := client.Ping(ctx).Err(); err != nil {
log.Fatalf("Could not connect to Redis: %v", err)
}
log.Println("Successfully connected to Redis.")
// 其他业务逻辑...
// 关闭客户端
defer client.Close()
}
CredentialsProvider 函数
CredentialsProvider 是 Redis 连接配置中的一个回调函数,用于在每次连接时动态提供用户名和密码。通过自定义该函数,你可以实现动态的认证信息更新,例如从安全存储中拉取凭据或根据上下文环境生成认证信息。
主要有以下应用场景:
- 安全性要求较高的场景:密码可能定期轮换或需要从安全存储(如 AWS Secrets Manager 或 Vault)中动态拉取最新的凭证。
- 多租户系统:不同租户可能需要不同的凭证,连接时动态生成合适的用户名和密码。
- 特定安全合规性需求:如 PCI DSS 等要求凭证动态生成或存储。
// 模拟的安全存储,提供动态凭证
func getCredentialsFromSecureStore() (username, password string) {
// 假设这里是从某个安全存储中获取凭证的逻辑
return "secure_user", "secure_password"
}
// 自定义 CredentialsProvider 函数
credentialsProvider := func() (username string, password string) {
return getCredentialsFromSecureStore()
}
// 配置 Redis 连接选项
opts := &redis.Options{
Addr: "localhost:6379", // Redis 服务地址
DB: 0, // 默认数据库
CredentialsProvider: credentialsProvider,
}
// 创建 Redis 客户端
rdb := redis.NewClient(opts)
ContextTimeoutEnabled说明
ContextTimeoutEnabled 用于控制客户端是否尊重 context.Context 提供的超时和截止时间。当这个选项启用时,客户端会根据传入的 context 对请求进行超时控制,一旦 context 达到设定的超时或截止时间,未完成的操作就会被取消。
在 Go 中,context.Context 是处理请求生命周期的关键机制之一,特别是需要进行超时控制、请求取消或者传递元数据的场景。启用 ContextTimeoutEnabled 后,可以根据 context 设定的超时和截止时间限制 Redis 操作的执行时间,避免长时间阻塞的操作。
使用场景:
- 网络不稳定或高延迟环境:在处理网络环境较差的场景时,启用
ContextTimeoutEnabled有助于避免 Redis 操作因网络波动导致的长时间阻塞,特别是在云提供商如 AWS 或 Google Cloud 等环境下,网络延迟时有波动,适当地设定超时可以提升系统的可靠性。 - 微服务架构:在微服务中,每个请求通常都有一个生命周期管理,使用
context.Context可以确保当请求超时时,相关的 Redis 操作也会被自动取消,以释放资源并提高系统效率。 - 避免死锁:如果某个 Redis 操作因未知原因无法完成(例如网络问题或 Redis 服务器负载过高),未启用超时可能导致操作一直阻塞。启用
ContextTimeoutEnabled后,当context规定的超时发生时,操作将自动取消,避免应用程序卡死
即使使用
context.Context的超时功能,官方建议不要禁用DialTimeout、ReadTimeout和WriteTimeout,因为 go-redis 在某些后台检查任务中不会使用context,而是依赖于这些连接超时设置。特别是在云环境下,不要将超时设置得太短(小于 1 秒),因为在网络延迟较大时,小的超时设置可能导致大量失败请求。
连接池配置说明
连接池(Connection Pool)通过复用连接来提高性能,减少每次请求都要创建新连接的开销。以下是连接池中几个重要参数的详细说明:
- PoolFIFO
PoolFIFO 控制连接池的队列策略。默认为 false,表示使用 LIFO(后进先出)策略;当设置为 true 时,使用 FIFO(先进先出)策略。
LIFO 可以提高性能,因为最近使用的连接往往是热连接,重用它们可以减少连接建立的成本。而 FIFO 更适合需要更快地关闭闲置连接的场景,例如在连接数有限的情况下,它可以帮助缩小连接池的规模,但性能上会有一定损耗。
- PoolSize
PoolSize 指定连接池的基本连接数量。默认是每个 CPU 核心 10 个连接。
适合高并发的业务场景。如果业务访问量较大,连接数不够用时,会导致频繁的创建新连接,增加延迟和资源消耗。合理调整 PoolSize 可以确保大多数请求都能从连接池中获取已有的连接,而不需要新建连接。
- PoolTimeout
PoolTimeout 在连接池中的所有连接都繁忙时,客户端等待连接的最大时间。超过这个时间后会返回错误。默认值是 ReadTimeout + 1秒。
适用于高负载的场景。设定合理的超时时间,避免在高并发时请求长时间阻塞。比如在对响应时间要求较高的业务场景下,可以设置较短的超时时间,使得请求及时返回错误,避免长时间等待而造成系统阻塞。
设置和获取值 Set, Get, Del
Set
// 设置一个键值对
err := rdb.Set(ctx, "name", "go-redis", 0).Err()
if err != nil {
fmt.Println("设置键值对失败", err)
return
}
Get
// 获取键值对
val, err := rdb.Get(ctx, "name").Result()
if err != nil {
fmt.Println("获取键值对失败", err)
return
}
fmt.Println("获取到的值为:", val)
Del
// 删除键值对
deleted, err := rdb.Del(ctx, "name").Result()
if err != nil {
fmt.Println("删除键值对失败", err)
return
}
fmt.Println("已成功删除的键值对的数量:", deleted)
递增 Incr
err := rdb.Set(ctx, "counter", 10, 0).Err()
if err != nil {
fmt.Println("设置初始值失败", err)
return
}
newVal, err := rdb.Incr(ctx, "counter").Result()
if err != nil {
fmt.Println("递增失败", err)
return
}
fmt.Println("递增后的值", newVal)
递减 Decr
newVal, err := rdb.Decr(ctx, "counter").Result()
if err != nil {
fmt.Println("递减失败", err)
return
}
fmt.Println("递减后的值", newVal)
批量设置MSet
err := rdb.MSet(ctx, "name", "Alice", "age", 30).Err()
if err != nil {
fmt.Println("批量设置键值对失败", err)
return
}
fmt.Println("批量设置成功")
批量获取MGet
value, err := rdb.MGet(ctx, "name", "age").Result()
if err != nil {
fmt.Println("批量获取键值对失败", err)
return
}
fmt.Println("批量获取键值对成功", value)
获取并设置 GetSet
获取键当前的值并设置一个新值
oldVal, err := rdb.GetSet(ctx, "name", "Bob").Result()
if err != nil {
fmt.Println("获取并设置值失败", err)
return
}
fmt.Println("旧值为", oldVal)
newVal, err := rdb.Get(ctx, "name").Result()
if err != nil {
fmt.Println("获取新值失败", err)
return
}
fmt.Println("新值为", newVal)
在原值上追加值 Append
err := rdb.Set(ctx, "greet", "Hello", 0).Err()
if err != nil {
fmt.Println("设置初始值失败", err)
return
}
// 追加新值
newLen err := rdb.Append(ctx, "greet", " World!").Result()
if err != nil {
fmt.Println("追加新值失败", err)
return
}
fmt.Println("新值长度", newLen)
获取字符串长度 StrLen
length, err := rdb.StrLen(ctx, "greet").Result()
if err != nil {
fmt.Println("获取字符串长度失败", err)
}
fmt.Println("字符串长度为:", length)
获取字符串的部分值 GetRange
part, err := rdb.GetRange(ctx, "greet", 0,4).Result()
if err != nil {
fmt.Println("获取字符串部分值失败", err)
}
fmt.Println("获取的字符串部分值为:", part)
获取并删除 GetDel
val, err := rdb.GetDel(ctx, "greet").Result()
if err != nil {
fmt.Println("获取并删除失败", err)
}
fmt.Println("获取并删除的值为:", val)
设置带过期时间的值 SetEx
err := rdb.SetEx(ctx, "temp", "expire", 10*time.Second).Err()
if err != nil {
fmt.Println("设置带过期时间的值失败", err)
}
// 获取key的剩余过期时间
ttl, err := rdb.TTL(ctx, "temp").Result()
fmt.Printf("TTL: %v\n", ttl)
// 立即设置 key 的过期时间到未来的时间戳
futureTimestamp := time.Now().Add(10 * time.Minute).Unix()
err = rdb.ExpireAt(ctx, "temp", time.Unix(futureTimestamp, 0)).Err()
if err != nil {
log.Fatalf("Error setting expire at: %v", err)
}
// 移除 key 的过期时间
err = rdb.Persist(ctx, "temp").Err()
if err != nil {
log.Fatalf("Error persisting key: %v", err)
}
设置不存在的值 SetNx
仅当键不存在时设置值
success, err := rdb.SetNX(ctx, "unique", "only if not exists", 0).Result()
if err != nil {
fmt.Println("设置不存在的值失败:", err)
return
}
if success {
fmt.Println("键值对设置成功(键不存在时)")
} else {
fmt.Println("键已存在,设置失败")
}
设置仅当键存在的值 SetXX
// 先设置一个值
err := rdb.Set(ctx, "exists", "initial", 0).Err()
if err != nil {
fmt.Println("设置初始值失败:", err)
return
}
// 仅当键已存在时设置值
success, err := rdb.SetXX(ctx, "exists", "updated", 0).Result()
if err != nil {
fmt.Println("设置存在的值失败:", err)
return
}
if success {
fmt.Println("键值对设置成功(键已存在时)")
} else {
fmt.Println("键不存在,设置失败")
}
批量设置不存在的值 MSetNx
// 批量设置不存在的键值对
success, err := rdb.MSetNX(ctx, "key1", "value1", "key2", "value2").Result()
if err != nil {
fmt.Println("批量设置不存在的键值对失败:", err)
return
}
if success {
fmt.Println("批量键值对设置成功(所有键不存在时)")
} else {
fmt.Println("某些键已存在,设置失败")
}
设置带参数的值 SetArgs
setArgs := redis.SetArgs{
Mode: "NX", //仅当键不存在时设置
TTL: 10*time.Second
}
err := rdb.SetArgs(ctx, "paramKey", "paramValue", setArgs).Err()
if err != nil {
fmt.Println("设置带参数的值失败", err)
}
获取两个字符串的最小公共子串 LCS
lcsQuery := redis.LCSQuery{
Key1: "string1",
Key2: "string2"
}
result, err := rdb.LCS(ctx, lcsQuery).Result()
if err != nil {
fmt.Println("获取最小公共子串失败", err)
return
}
fmt.Println("最小子串为:", result)
递增浮点数的值 IncrByFloat
err := rdb.Set(ctx, "fioatKey", 10.5, 0).Err()
newVal, err := rdb.IncrByFloat(ctx, "floatKey", 2.5)
设置字符串指定位置的值 SetRange
err := rdb.Set(ctx, "rangeKey", "Hello Redis", 0).Err()
newLength, err := rdb.SetRange(ctx, "rangeKey", 6, "Golang").Result()
if err != nil {
fmt.Println("设置指定位置的值失败", err)
}
fmt.Println("新值长度", newLength)
hash操作 HSet HGet HDel
// 设置哈希键值对
err := rdb.HSet(ctx, "user", map[string]interface{}{"name": "go-redis", "age": 20}).Err()
if err != nil {
fmt.Println("设置哈希键值对失败", err)
return
}
// 获取哈希键值对
val, err := rdb.HGet(ctx, "user", "name").Result()
if err != nil {
fmt.Println("获取哈希键值对失败", err)
return
}
fmt.Println("获取到的值为:", val)
// 删除哈希键值对
deleted, err := rdb.HDel(ctx, "user", "name", "age").Result()
if err != nil {
fmt.Println("删除哈希键值对失败", err)
return
}
fmt.Println("已成功删除的哈希键值对的数量:", deleted)
检查hash表中指定字段是否存在 HExists
result := rdb.HExists(ctx, "user", "name")
fmt.Println("result.Val()") // 返回true/false
获取哈希表中所有字段和值 HGetAll
result := rdb.HGetAll(ctx, "user")
fmt.Println(result.Val()) // 输出哈希表中的所有字段和值
为哈希表中指定字段的整数值加上增量值 HIncrBy
result := rdb.HIncrBy(ctx, "myhash", "field1", 10)
fmt.Println(result.Val()) // 输出增加后的值
为哈希表中指定字段的浮点数加上增量值 HIncrByFloat
result := rdb.HIncrByFloat(ctx, "myhash", "field1", 10.5)
fmt.Println(result.Val()) // 输出增加后的值
获取哈希表中所有字段名 HKeys
result := rdb.HKeys(ctx, "myhash")
fmt.Println(result.Val()) // 输出所有字段名
获取哈希表中字段的数量 HLen
result := rdb.HLen(ctx, "myhash")
fmt.Println(result.Val()) // 输出字段的数量
获取哈希表中一个或多个指定字段的值 HMGet
result := rdb.HMGet(ctx, "myhash", "field1", "field2")
fmt.Println(result.Val()) // 输出字段的值数组
仅当字段不存在时,设置指定的值 HSetNx
result := rdb.HSetNX(ctx, "myhash", "field1", "value1")
fmt.Println(result.Val()) // 输出true表示设置成功,false表示字段已存在
增量迭代哈希表中的字段 HScan
// HScan(ctx, key string, cursor uint64, match string, count int64) *ScanCmd
result := rdb.HScan(ctx, "myhash", 0, "*", 10)
fmt.Println(result.Val()) // 输出匹配的字段和值
//- cursor:扫描的游标,初始值为 0。
// - match:匹配模式,这里使用 `*` 匹配以任意字段。
// - count:每次扫描提示返回的元素数量。
增量迭代哈希表中的字段 (不包括值)HScanNoValues
// HScanNoValues(ctx, key string, cursor uint64, match string, count int64) *ScanCmd result := rdb.HScanNoValues(ctx, "myhash", 0, "*", 10)
fmt.Println(result.Val()) // 输出匹配的字段
随机获取哈希表中的一个或多个字段 HRandField
// HRandField(ctx, key string, count int) *StringSliceCmd
result := rdb.HRandField(ctx, "myhash", 2)
fmt.Println(result.Val()) // 输出随机获取的字段
随机获取哈希表中的一个或多个字段及其值 HRandFieldWithValues
// HRandFieldWithValues(ctx, key string, count int) *KeyValueSliceCmd
result := rdb.HRandFieldWithValues(ctx, "myhash", 2)
fmt.Println(result.Val()) // 输出随机获取的字段及其值
设置哈希表中指定字段的过期时间 HExpire
// HExpire(ctx, key string, expiration time.Duration, fields ...string) *IntSliceCmd result := rdb.HExpire(ctx, "myhash", 10*time.Second, "field1", "field2") fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间(以秒为单位)并附加过期选项 HExpireWithArgs
// HExpireWithArgs(ctx, key string, expiration time.Duration, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
result := rdb.HExpireWithArgs(ctx, "myhash", 10*time.Second, redis.HExpireArgs{}, "field1", "field2")
fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间(以毫秒为单位)HPExpire
// HPExpire(ctx, key string, expiration time.Duration, fields ...string) *IntSliceCmd result := rdb.HPExpire(ctx, "myhash", 10000*time.Millisecond, "field1", "field2") fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间(以毫秒为单位)并附加过期选项 HPExpireWithArgs
// HPExpireWithArgs(ctx, key string, expiration time.Duration, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
result := rdb.HPExpireWithArgs(ctx, "myhash", 10000*time.Millisecond, redis.HExpireArgs{}, "field1", "field2")
fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间点 HExpireAt
// HExpireAt(ctx, key string, tm time.Time, fields ...string) *IntSliceCmd
result := rdb.HExpireAt(ctx, "myhash", time.Now().Add(10*time.Second), "field1", "field2") fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间点并附加过期选项 HExpireAtWithArgs
// HExpireAtWithArgs(ctx, key string, tm time.Time, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
result := rdb.HExpireAtWithArgs(ctx, "myhash", time.Now().Add(10*time.Second), redis.HExpireArgs{}, "field1", "field2")
fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间点(以毫秒为单位) HPExpireAt
// HPExpireAt(ctx, key string, tm time.Time, fields ...string) *IntSliceCmd
result := rdb.HPExpireAt(ctx, "myhash", time.Now().Add(10000*time.Millisecond), "field1", "field2")
fmt.Println(result.Val()) // 输出设置成功的字段数量
设置哈希表中指定字段的过期时间点(以毫秒为单位)并附加过期选项 HPExpireAtWithArgs
// HPExpireAtWithArgs(ctx, key string, tm time.Time, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
result := rdb.HPExpireAtWithArgs(ctx, "myhash", time.Now().Add(10000*time.Millisecond), redis.HExpireArgs{}, "field1", "field2")
fmt.Println(result.Val()) // 输出设置成功的字段数量
移除哈希表中指定字段的过期时间,使其永久有效HPersist
// HPersist(ctx, key string, fields ...string) *IntSliceCmd
result := rdb.HPersist(ctx, "myhash", "field1", "field2")
fmt.Println(result.Val()) // 输出设置成功的字段数量
获取哈希表中指定字段的过期时间HExpireTime
// HExpireTime(ctx, key string, fields ...string) *IntSliceCmd
result := rdb.HExpireTime(ctx, "myhash", "field1", "field2")
fmt.Println(result.Val()) // 输出字段的剩余过期时间(秒)
获取哈希表中指定字段的过期时间(以毫秒为单位)HPExpireTime
// HPExpireTime(ctx, key string, fields ...string) *IntSliceCmd
result := rdb.HPExpireTime(ctx, "myhash", "field1", "field2")
fmt.Println(result.Val()) // 输出字段的剩余过期时间(毫秒)
获取哈希表中指定字段的剩余生存时间(以秒为单位)HTTL
// HTTL(ctx, key string, fields ...string) *IntSliceCmd
result := rdb.HTTL(ctx, "myhash", "field1", "field2")
fmt.Println(result.Val()) // 输出字段的剩余生存时间(秒)
获取哈希表中指定字段的剩余生存时间(以毫秒为单位)HPTTL
// HPTTL(ctx, key string, fields ...string) *IntSliceCmd
result := rdb.HPTTL(ctx, "myhash", "field1", "field2")
fmt.Println(result.Val()) // 输出字段的剩余生存时间(毫秒)
列表操作 LPush Lpop RPush RPop LLen LRange
// 向列表左侧添加元素
err := rdb.LPush(ctx, "list", "a", "c").Err()
if err != nil {
fmt.Println("向列表左侧添加元素失败", err)
return
}
// 获取并删除列表的第一个元素
val, err := rdb.LPop(ctx, "list").Result()
if err != nil {
fmt.Println("获取并删除列表的第一个元素失败", err)
return
}
fmt.Println("获取到的值为:", val)
// 向列表右侧添加元素
err = rdb.RPush(ctx, "list", "b").Err()
if err != nil {
fmt.Println("向列表右侧添加元素失败", err)
return
}
// 获取并删除列表的最后一个元素
val, err = rdb.RPop(ctx, "list").Result()
if err != nil {
fmt.Println("获取并删除列表的最后一个元素失败", err)
return
}
fmt.Println("获取到的值为:", val)
// 获取列表的长度
length, err := rdb.LLen(ctx, "list").Result()
if err != nil {
fmt.Println("获取列表的长度失败", err)
return
}
fmt.Println("列表长度为:", length)
// 获取列表中的所有元素
vals, err := rdb.LRange(ctx, "list", 0, -1).Result()
if err != nil {
fmt.Println("获取列表中的所有元素失败", err)
return
}
fmt.Println("列表中的所有元素为:", vals)
// 删除列表
deleted, err := rdb.Del(ctx, "list").Result()
if err != nil {
fmt.Println("删除列表失败", err)
return
}
fmt.Println("已成功删除的键值对的数量:", deleted)
// 查询列表是否存在
exists, err := rdb.Exists(ctx, "list").Result()
if err != nil {
fmt.Println("查询列表是否存在失败", err)
return
}
fmt.Println("列表存在:", exists)
无序集合操作 SAdd SPop SIsMember SMembers
// 向集合中添加元素
err := rdb.SAdd(ctx, "set", "a", "b").Err()
if err != nil {
fmt.Println("向集合中添加元素失败", err)
return
}
// 获取并删除集合中的随机一个元素
val, err := rdb.SPop(ctx, "set").Result()
if err != nil {
fmt.Println("获取并删除集合中的随机一个元素失败", err)
return
}
fmt.Println("获取到的值为:", val)
// 判断元素是否在集合中
exists, err := rdb.SIsMember(ctx, "set", "a").Result()
if err != nil {
fmt.Println("判断元素是否在集合中失败", err)
return
}
fmt.Println("元素存在:", exists)
// 获取集合中的所有元素
tags, err := rdb.SMembers(ctx, "set").Result()
if err != nil {
fmt.Println("获取集合中的所有元素失败", err)
return
}
fmt.Println("集合中的所有元素为:", tags)
有序集合操作 ZAdd ZRangeWithScores
// 向有序集合中添加元素
err := rdb.ZAdd(ctx, "zset", redis.Z{Score: 100, Member: "Alice"}, redis.Z{Score: 200, Member: "Bob"}).Err()
if err != nil {
fmt.Println("向有序集合中添加元素失败", err)
return
}
// 获取有序集合中的所有元素
tags, err := rdb.ZRangeWithScores(ctx, "zset", 0, -1).Result()
if err != nil {
fmt.Println("获取有序集合中的所有元素失败", err)
return
}
for _, tag := range tags {
fmt.Printf("%s:%v\n", tag.Member.(string), tag.Score)
}