1. go-redis是什么

官方用语:Go client for Redis Server and Redis Cluster

官方列出三个主要的点:
  • All flavors:Out-of-the-box works with Redis Server, Redis Cluster, Redis Sentinel, and even Ring of Redis Servers.

  • Type-safe:go-redis provides types for most Redis commands so you can work with well-structured replies.

  • Feature-rich:We support pipelines, transactions, publish/subscribe, Lua scripts, mocks, distributed locks, and more.


一句话理解:它是开箱即用,它是一款支持redis服务器、redis集群、redis Sentinel,redis服务器环的客户端,它具备类型安全,go-redis为大多数redis命令提供了类型,因此您可以使用结构良好的回复,它功能丰富,支持管道、事务、发布/订阅、Lua脚本、mocks、分布式锁等。

另外,go-redis/redis也是Redis官方比较推荐的一款操作Redis的client。
■ ■■■■

go get github.com/go-redis/redis/v8
import "github.com/go-redis/redis/v8"


rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
  Password: "", // 这里是密码
DB: 0, // 数据库
})
opt, err := redis.ParseURL("redis://localhost:6379/0")
if err != nil {
panic(err)
}


rdb := redis.NewClient(opt)
package main


import (
"context"
"fmt"


"github.com/go-redis/redis/v8"
)


// 快速入门:
// 连接、执行命令


func main() {
ctx := context.Background()


// 连接
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
    Password: "",
    DB:      0,
})
fmt.Println(rdb) // Redis<localhost:6379 db:0>

  // 执行命令
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}


val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val) // key value


val2, err := rdb.Get(ctx, "key2").Result()
if err == redis.Nil {
fmt.Println("key2 does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("key2", val2)
}
  // key2 does not exist
}
package main


import (
"context"
"fmt"
"time"


"github.com/go-redis/redis/v8"
)


func main() {
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}


// Set 设置
err = rdb.Set(ctx, "key", "thisisavalue", 0).Err() // 0表示永不过期
if err != nil {
panic(err)
}
err = rdb.Set(ctx, "key2", "this is a value2", time.Minute * 2).Err() // key2将会在两分钟后过期失效
if err != nil {
panic(err)
}
fmt.Println("set success")


// SetEX 设置并指定过期时间
err = rdb.SetEX(ctx, "key3", "this is a value3", time.Hour * 2).Err()
if err != nil {
panic(err)
}
fmt.Println("SetEX success")


// SetNX 设置并指定过期时间
_, err = rdb.SetNX(ctx, "key4", "this is a value4", time.Minute).Result()
if err != nil {
fmt.Println("SetNX failed, key4已经存在", err)
}
fmt.Println("SetNX success")


// Get 获取
result, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key值:", result)

result, err = rdb.Get(ctx, "key5").Result()
  // redis.Nil来区分空字符串应答和Nil应答(键不存在)
  if err == redis.Nil {
fmt.Println("key5不存在")
} else if err != nil {
panic(err)
} else {
fmt.Println("key5值为:", result)
}


// GetRange 获取字符串值的子字符
result, err = rdb.GetRange(ctx, "key", 1, 4).Result()
if err != nil {
panic(err)
}
fmt.Printf("GetRange截取key值为: %v\n", result)
}


// 打印结果如下:
/*
set success
SetEX success
SetNX success
key值: thisisavalue
key5不存在
GetRange截取key值为: hisi
*/


下面是增减量的API:

  • Incr:将 key 中储存的数字值增加1

  • IncrBy:将 key 所储存的值加上给定的增量值

  • Decr:将 key 中储存的数字值减1

  • DecrBy:key 所储存的值减去给定的减量值


这些API的演示代码如下:

package main


import (
"context"
"fmt"


"github.com/go-redis/redis/v8"
)


func main() {
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}


// Incr 增加+1
result, err := rdb.Incr(ctx, "count").Result()
if err != nil {
panic(err)
}
fmt.Printf("count值为: %v\n", result)


// IncrBy 按指定步长增加
result, err = rdb.IncrBy(ctx, "count", 2).Result()
if err != nil {
panic(err)
}
fmt.Printf("count值为: %v\n", result)


// Decr 减少-1
result, err = rdb.Decr(ctx, "count").Result()
if err != nil {
panic(err)
}
fmt.Printf("count值为: %v\n", result)


// DecrBy 按指定步长减少
result, err = rdb.DecrBy(ctx, "count", 2).Result()
if err != nil {
panic(err)
}
fmt.Printf("count值为: %v\n", result)
}


// 打印结果如下:
/*
count值为: 1
count值为: 3
count值为: 2
count值为: 0
*/

■ ■■■■


6. 操作redis List类型

Redis 列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。

下面是go-redis操作redis List列表类型的一些API:
  • LPush:在列表的左侧加入数据

  • LLen:获取链表元素个数

  • LIndex:获取列表某下标对应元素

  • LInsert:向某个索引位置插入一个元素

  • LSet:设置列表某个索引位置的值

  • Lpop:从列表左侧弹出数据

  • LRange:获取某个索引范围里的元素

  • LTrim:对一个列表进行修剪,只让列表保留指定区间内的元素,不在指定区间之内的元素都将被删除


这些API的演示代码如下:

package main


import (
"context"
"fmt"


"github.com/go-redis/redis/v8"
)


func main() {
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}


// LPush(ctx, key, values...) 在列表的左侧加入数据
n, err := rdb.LPush(ctx, "test_list", 1, 2, 3, 4, 5, 6).Result()
if err != nil {
panic(err)
}
fmt.Println(n)


// LLen(ctx, key) 获取链表元素个数
len, err := rdb.LLen(ctx, "test_list").Result()
if err != nil {
panic(err)
}
fmt.Println("test_list的长度:", len)


// LIndex(ctx, key, index) 获取列表某下标对应元素
val, err := rdb.LIndex(ctx, "test_list", 2).Result() // 索引从0数起。
if err != nil {
panic(err)
}
fmt.Println("index是2的值:", val)


// LInsert(ctx, key, op, pivot, value) 向某个索引位置插入一个元素
err = rdb.LInsert(ctx, "test_list", "before", "2", 8).Err() // 在test_list列表的2的前面插入8。
if err != nil {
panic(err)
}
fmt.Println("插入成功")


// LSet(ctx, key, index, value) 设置列表某个索引位置的值
err = rdb.LSet(ctx, "test_list", 1, 9).Err() // 给索引为1 的位置设置为9。索引从0数起。
if err != nil {
panic(err)
}
fmt.Println("设置成功")


// LPop(ctx, key) 从列表左侧弹出数据
val, err = rdb.LPop(ctx, "test_list").Result()
if err != nil {
panic(err)
}
fmt.Println("从列表左侧弹出元素:", val)


// LRange(ctx, key, start, stop) 获取某个索引范围里的元素
vals, err := rdb.LRange(ctx, "test_list", 1, 4).Result()
if err != nil {
panic(err)
}
fmt.Println("获取索引1到4的值:", vals)


// LTrim(ctx, key, start, stop) 对一个列表进行修剪,
  // 只让列表保留指定区间内的元素,不在指定区间之内的元素都将被删除
val, err = rdb.LTrim(ctx, "test_list", 1, 4).Result() // 此时只剩下1到4范围内的值
if err != nil {
panic(err)
}
fmt.Println("val值:", val)
}


// 打印结果如下:
/*
6
test_list的长度: 6
index是2的值: 4
插入成功
设置成功
从列表左侧弹出元素: 6
获取索引1到4的值: [4 3 8 2]
val值: OK
*/
■ ■■■■

7. 操作redis Hash类型

Redis hash 是一个键值(key=>value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。


下面是go-redis操作redis Hash类型的一些API:
  • HSet:给key设置field和value

  • HGet:获取key某个field的value

  • HMset:给key批量设置field和value

  • HLen:获取键值对个数

  • HGetAll:获取全部键值对元素

  • HKeys:获取所有的key

  • HIncrBy:增加,成功返回增加后的值

  • HDel:删除键值对元素

  • HExists:检查key某个field是否存在


这些API的演示代码如下:
package main


import (
"context"
"fmt"


"github.com/go-redis/redis/v8"
)


func main() {
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
_, err := rdb.Ping(ctx).Result() // PING, <nil>
if err != nil {
fmt.Println("connect redis failed:", err)
return
}


// HSet 给key设置field和value
result, err := rdb.HSet(ctx, "user1", "name", "zhangsan").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1

// HMSet 批量设置
rdb.HMSet(ctx, "user1", map[string]interface{}{"age": 18, "sex": "male"})

// HGet 获取某个field的value
name, err := rdb.HGet(ctx, "user1", "name").Result()
if err != nil {
panic(err)
}
fmt.Println(name) // zhangsan


// HMGet 批量获取field的value
fields, err := rdb.HMGet(ctx, "user1", "name", "age").Result()
if err != nil {
panic(err)
}
fmt.Println(fields) // [zhangsan 18]


// HLen 获取键值对个数
len, err := rdb.HLen(ctx, "user1").Result()
if err != nil {
panic(err)
}
fmt.Println(len) // 3


// HGetAll 获取全部元素
all, err := rdb.HGetAll(ctx, "user1").Result()
if err != nil {
panic(err)
}
fmt.Println(all) // map[age:18 name:zhangsan sex:male]


// HKeys 获取所有的key
keys, err := rdb.HKeys(ctx, "user1").Result()
if err != nil {
panic(err)
}
fmt.Println(keys) // [name age sex]


// HIncrBy 增加,成功返回增加后的值
age, err := rdb.HIncrBy(ctx, "user1", "age", 2).Result()
if err != nil {
panic(err)
}
fmt.Println(age) // 20


// HDel 删除键值对元素
result, err = rdb.HDel(ctx, "user1", "name").Result()
if err != nil {
panic(err)
}
fmt.Println(result) // 1


// HExists 检查某个元素是否存在
  fmt.Println(rdb.HExists(ctx, "user1","name"))  // hexists user1 name: false
}


// 打印结果如下:
/*
1
zhangsan
[zhangsan 18]
3
map[age:18 name:zhangsan sex:male]
[name age sex]
20
1
hexists user1 name: false
*/