Go操作Redis

Redis是一个开源的内存数据库,Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外,通过复制、持久化和客户端分片等特性,我们可以很方便地将Redis扩展成一个能够包含数百GB数据、每秒处理上百万次请求的系统。

Redis支持的数据结构:

  • 字符串(string)
  • 哈希(hash)
  • 列表(list)
  • 集合(set)
  • 有序集合(sorted set)
  • 位图 ( Bitmaps )
  • 基数统计 ( HyperLogLogs )

Redis应用场景:

  • 缓存系统,减轻主数据库(MySQL)的压力
  • 计数场景,比如微博、抖音中的关注数和粉丝数
  • 热门排行榜,需要排序的场景特别适合使用ZSET
  • 利用LIST可以实现队列的功能

关于Redis的介绍这里不再多说。可以参考Redis入门 笔记

关于Redis的安装也不再多说,本地安装和docker安装(Docker安装Redis)。

区别于另一个比较常用的Go语言redis client库:redigo,我们这里采用https://github.com/go-redis/redis连接Redis数据库并进行操作,因为go-redis支持连接哨兵及集群模式的Redis。(See Comparing go-redis vs redigo.)

golang redis快速入门教程(老版本,没有升级到V8)

Go操作Redis实战(go-redis v8)

Github:go -redis

go-redis V8新版本相关

Go Redis官网建议多看官网!

go-redis v8 Documentation

If you are using Redis 6, install go-redis/v8:

1
go get github.com/go-redis/redis/v8

If you are using Redis 7, install go-redis/v9 (currently in beta):

1
go get github.com/go-redis/redis/v9

客户端连接

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.Ping(ctx).Result()
if err != nil {
log.Fatalln("连接redis出错,错误信息:", err)
}
fmt.Println("成功连接redis")
fmt.Println(result) // PONG
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

关于Context,官网是这样说的:

Every Redis command accepts a context that you can use to set timeouts or propagate some information, for example, tracing context.

1
ctx := context.Background()

Background返回一个非空的Context。 它永远不会被取消,没有值,也没有期限。 它通常在main函数,初始化和测试时使用,并用作传入请求的顶级上下文。

基本指令

基本指令

Keys():根据正则获取keys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
keys, err := rdb.Keys(ctx, "*").Result() // *表示获取所有的key
if err != nil {
log.Fatalln(err)
}
fmt.Println(keys)
fmt.Printf("%T", keys) // []string
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

Type():获取key对应值得类型

Type():获取一个key对应值的类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
vType, err := rdb.Type(ctx, "hash1").Result() // 获取key为test的类型
if err != nil {
log.Fatalln(err)
}
fmt.Println(vType)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

Del():删除缓存项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
n, err := rdb.Del(ctx, "test", "hello").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("成功删除了", n, "个key")
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

Exists():检测缓存项是否存在

Exists():用于检测某个key是否存在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
n, err := rdb.Exists(ctx, "test").Result()
if err != nil {
log.Fatalln(err)
}
if n > 0 {
fmt.Println("存在")
} else {
fmt.Println("不存在")
}
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

注:Exists()方法可以传入多个key,返回的第一个结果表示存在的key的数量,不过工作中我们一般不同时判断多个key是否存在,一般就判断一个key,所以判断是否大于0即可如果判断判断传入的多个key是否都存在,则返回的结果的值要和传入的key的数量相等

1
func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {...}

Expire()&ExpireAt():设置有效期

使用场景:设置好key后,再设置key的有效期。

  • Expire():设置某个时间段(time.Duration)后过期
  • ExpireAt():在某个时间点(time.Time)过期失效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main

import (
"context"
"fmt"
"log"
"time"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.Expire(ctx, "test1", time.Minute*3).Result()
if err != nil {
log.Fatalln(err)
}
if result {
fmt.Println("设置成功! test1将于3分钟后过期")
} else {
fmt.Println("设置失败!")
}

//result, err := rdb.ExpireAt(ctx, "test2", time.Now().Add(time.Second*30)).Result()
// string转time.Time
str := "2022-07-14T12:52:28Z"
t, err := time.Parse("2006-01-02T15:04:05Z", str)
if err != nil {
log.Fatalln(err)
}
b, err := rdb.ExpireAt(ctx, "test2", t).Result()
if b {
fmt.Println("设置成功! test2将于2022-07-14 12:52:28过期")
} else {
fmt.Println("设置失败!")
}

}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

TTL(),PTTL():获取有效期

  • TTL():获取某个键的剩余有效期(单位:秒(s))
  • PTTL():获取某个键的剩余有效期(单位:毫秒(ms))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"context"
"fmt"
"log"
"time"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
rdb.Expire(ctx, "test", time.Minute*1) // 设置1分钟后过期

ttl, err := rdb.TTL(ctx, "test").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(ttl)
pttl, err := rdb.PTTL(ctx, "test").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(pttl)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

DBSize():查看当前数据库key的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
num, err := rdb.DBSize(ctx).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(num)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

FlushDB():清空当前数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
// 清空当前数据库,因为连接的是索引为10的数据库,所以清空的就是10号数据库
result, err := rdb.FlushDB(ctx).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(result) // OK
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

FlushAll():清空所有数据库

慎用!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.FlushAll(ctx).Result() // 清空所有数据库,慎用!
if err != nil {
log.Fatalln(err)
}
fmt.Println(result) // OK
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "192.168.219.101:6379", // redis地址
Password: "1234", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

字符串(string)类型

这里先介绍常用的字符串操作,此外,字符串(string)类型还有MGet()Mset()MSetNX()等同时操作多个key的方法,详见:https://pkg.go.dev/github.com/go-redis/redis/v8

Set() 设置

仅仅支持字符串(包含数字)操作,不支持内置数据编码功能。如果需要存储Go的非字符串类型,需要提前手动序列化,获取时再反序列化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"context"
"log"
"time"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
err := rdb.Set(ctx, "hello", "world", 0).Err() // 0表示永不过期
if err != nil {
log.Fatalln(err)
}
err = rdb.Set(ctx, "test", "即将过期", time.Minute*1).Err() // test这个key将在1分钟后过期
if err != nil {
log.Fatalln(err)
}
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SetEX() 设置并指定过期时间

设置键的同时,设置过期时间。

当某个key已经存在时,可以用SetEX()来对这个key设置过期时间。SetEX()不管该key是否已经存在缓存中,直接覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"context"
"log"
"time"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
err := rdb.SetEX(ctx, "hello", "world", time.Minute*3).Err() // 0表示永不过期
if err != nil {
log.Fatalln(err)
}
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SetNX() 设置并指定过期时间

SetEX()SetNX()的区别:

  • SetEX()不管该key是否已经存在缓存中,直接覆盖

  • SexNX()仅当key不存在的时候才设置,如果key已经存在则不做任何操作

还有一点需要注意:如果我们想知道我们调用SetNX()是否设置成功了,可以接着调用Result()方法,返回的第一个值表示是否设置成功了:

  • 如果返回false,说明缓存Key已经存在,此次操作虽然没有错误,但是是没有起任何效果的
  • 如果返回true,表示在此之前key是不存在缓存中的,操作是成功的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"context"
"fmt"
"log"
"time"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
ok, err := rdb.SetNX(ctx, "hello", "world", time.Minute*5).Result()
if err != nil {
log.Fatalln(err)
}
if ok {
fmt.Println("key不存在,操作成功")
} else {
fmt.Println("key存在,操作不成功")
}
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

Get() 获取

如果要获取的key在缓存中并不存在,Get()方法将会返回redis.Nil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.Get(ctx, "hello").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)

val2, err := rdb.Get(ctx, "test1").Result()
if err != nil {
if err == redis.Nil {
fmt.Println("key不存在")
} else {
log.Fatalln(err)
}
return
}
fmt.Println(val2)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

GetRange() 字符串截取

GetRange():用来截取字符串的部分内容,最后两个参数分别是索引的开始位置和结束位置(左闭右闭,[start,end])。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.GetRange(ctx, "test", 0, 3).Result() // [0,3]
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

注:即使key不存在,调用GetRange()也不会报错,只是返回的截取结果是空"",可以使用fmt.Printf("%q\n", val)来打印测试

Incr() 增加(+1)

Incr()IncrBy()都是操作数字,对数字进行增加的操作,incr()是执行原子加1操作,incrBy()是增加指定的数。

所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何context witch(切换到另一个线程)。

  • 在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只能发生于指令之间
  • 在多线程中,不能被其它进程(线程)打断的操作叫原子操作

Redis单命令的原子性主要得益于Redis的单线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.Get(ctx, "number").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("val为:", val) // val为: 1
// 执行Incr():增加(+1)操作
val2, err := rdb.Incr(ctx, "number").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("Incr后的val为:", val2) // Incr后的val为: 2
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

IncrBy() 增加(按指定步长)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.Get(ctx, "number").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("val为:", val) // val为: 2
// 执行IncrBy():增加(按指定步长)操作
val2, err := rdb.IncrBy(ctx, "number", 10).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("IncrBy后的val为:", val2) // IncrBy后的val为: 12
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

Decr() 减少(-1)

Decr()DecrBy()方法是对数字进行减的操作,和Incr()IncrBy()正好相反。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.Get(ctx, "number").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("val为:", val) // val为: 12
// 执行Decr():减少(-1)操作
val2, err := rdb.Decr(ctx, "number").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("Decr后的val为:", val2) // Decr后的val为: 11
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

DecrBy() 减少(按指定步长)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.Get(ctx, "number").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("val为:", val) // val为: 11
// 执行DecrBy():减少(按指定步长)操作
val2, err := rdb.DecrBy(ctx, "number", 10).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("DecrBy后的val为:", val2) // DecrBy后的val为: 1
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

Append() 追加

Append():往字符串后面追加元素,返回值是字符串的总长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
str, err := rdb.Get(ctx, "test1").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(str) // hello,
// 注意Append()返回值是添加后的字符串长度
length, err := rdb.Append(ctx, "test1", "world!").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(length) // 14

str, err = rdb.Get(ctx, "test1").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(str) // hello,world!
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

StrLen() 获取长度

StrLen():获取字符串的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
length, err := rdb.StrLen(ctx, "test").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(length)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

哈希(hash)类型

Redis hash是一个string类型的 field(字段) 和 any类型的value(值) 的映射表,hash特别适合用于存储对象。(之前在gobang项目中用hash开存储go的struct)。Redis 中每个hash可以存储2^32 - 1键值对(40多亿)。

当前服务器一般都是将用户登录信息保存到Redis中,这里存储用户登录信息就比较适合用hash表。hash表比string更合适。

如果我们选择使用string类型来存储用户的信息的时候,我们每次存储的时候就得先序列化成字符串才能存储到redis;从redis拿到用户信息后又得反序列化成数组或对象,这样开销比较大。如果使用hash的话我们通过key(用户ID)+field(属性标签)就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。

HSet() 设置

HSet()支持如下格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
"context"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
rdb.HSet(ctx, "user", "key1", "value1", "key2", "value2") // 直接在后面依次指定key和value

s := []string{"id", "123", "name", "张三"}
rdb.HSet(ctx, "user", s) // 通过string切片slice

m := make(map[string]any, 0)
m["sex"] = "男"
m["age"] = 20
rdb.HSet(ctx, "user", m) // 通过map
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

redis中的hash值:

HMset() 批量设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"context"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
m := map[string]any{
"name": "李四",
"id": 123,
}
rdb.HMSet(ctx, "student", m)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

redis成功存储hash值:

HGet() 获取某个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.HGet(ctx, "student", "name").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

HGetAll() 获取全部元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
user, err := rdb.HGetAll(ctx, "user").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(user) // map[age:20 id:123 key1:value1 key2:value2 name:张三 sex:男]
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

HDel() 删除某个元素

HDel()支持一次删除多个元素。在参数中写入要删除的hash类型的key即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.HDel(ctx, "user", "key1", "key2").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(result) // 2
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

删除后的user:

HExists() 判断元素是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
exist, err := rdb.HExists(ctx, "student", "id").Result()
exist2, err := rdb.HExists(ctx, "student", "age").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(exist) // true
fmt.Println(exist2) // false
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

HLen() 获取长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
length, err := rdb.HLen(ctx, "user").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(length) // 4
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

此时的user:

列表(list)类型

Redis list是按插入顺序排序的string列表。可以在列表的**头部(左边)尾部(右边)**添加元素。列表可以包含2^32 - 1个元素(40多亿)。

LPush() 将元素从左侧压入链表

LPush():将数据从左侧压入链表。当指定的key不存在时,会自动创建key。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
// 返回值是当前列表元素的数量
n, err := rdb.LPush(ctx, "list", 1, 2, "hello", "world").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(n) // 4
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

注意LPush()是从左侧压入数据的,所以list如下:

RPush() 将元素从右侧压入链表

RPush():将数据从右侧压入链表。当指定的key不存在时,会自动创建key。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
// 返回值是当前列表元素的数量
n, err := rdb.RPush(ctx, "list2", 1, 2, "hello", "world").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(n) // 4
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

RPush()是从右侧压入数据的,所以list2如下:

LInsert() 在某个位置插入新元素

函数签名:

1
func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd

具体点说,是在某个元素的前面或后面插入新元素。

  • op指定为before:在pivot前面插入新元素
  • op指定为after:在pivot后面插入新元素

注意:即使key列表里有多个值为hello的元素,也只会在第一个值为hello的元素前面插入3,并不会在所有值为hello的前面插入3。

客户端还提供了从前面插入和从后面插入的LInsertBefore()LInsertAfer()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
// 在名为list2的缓存项值为hello的元素前面插入一个值,值为3
n, err := rdb.LInsert(ctx, "list2", "before", "hello", "3").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(n) // 5
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

LSet() 设置某个元素的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"context"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
err := rdb.LSet(ctx, "list", 1, 100).Err() // 索引是从0开始的
if err != nil {
log.Fatalln(err)
}
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

LLen() 获取列表元素个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
length, err := rdb.LLen(ctx, "list").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(length)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

LIndex() 根据索引获取列表元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.LIndex(ctx, "list", 2).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

LRange() 获取某个选定范围的元素集

范围是左闭右闭([start,end]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
list, err := rdb.LRange(ctx, "list", 0, 2).Result() // [0,2]
if err != nil {
log.Fatalln(err)
}
fmt.Println(list) // [1 100 hello]
fmt.Printf("%T\n", list) // []string
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

LPop() 从列表左侧弹出数据

Push和Pop操作,跟数据结构中的类似。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.LPop(ctx, "list").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

RPop() 从列表右侧弹出数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.RPop(ctx, "list").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

LRem() 根据值移除元素

函数签名:

1
func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
  • count:要删除元素的个数
  • value:根据指定值删除该元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.LRem(ctx, "list", 2, "hello").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println("删除了", val, "个元素") // 删除了 2 个元素
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

删除前:

删除后:

集合(set)类型

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动去重的,当你需要存储一个列表数据,又不希望出现重复数据,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的接口,这是list所不能提供的。

Redis的setstring类型的无序集合。它底层其实是一个value为null的hash表,所以添加、删除、查找的复杂度都是O(1)。

集合数据的特征:

  1. 元素不能重复,保持唯一性
  2. 元素无序,不能使用索引(下标)操作

SAdd() 添加元素

当指定的key不存在时,会自动创建key。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"context"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
rdb.SAdd(ctx, "team", "张三", "lisi", "tom")
rdb.SAdd(ctx, "team", "王五")
rdb.SAdd(ctx, "team", "张三") // 重复添加无效,因为张三已经被添加到team集合中了
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SPop() 随机弹出一个元素

SPop():从集合中随机弹出元素的,如果想一次弹出多个元素,可以使用SPopN()方法。(set的无序性,所以是随机的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.SPop(ctx, "team").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SPopN() 随机弹出多个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.SPopN(ctx, "team", 2).Result() // 指定随机弹出两个
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
fmt.Printf("%T", val) // []string
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SRem() 删除集合里指定的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
n, err := rdb.SRem(ctx, "team", "张三").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(n) // 1
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SMembers() 获取所有成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.SMembers(ctx, "team").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(result)
fmt.Printf("%T", result) // []string
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SIsMember() 判断元素是否在集合中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
exists, err := rdb.SIsMember(ctx, "team", "张三").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(exists)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SCard() 获取集合元素个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
length, err := rdb.SCard(ctx, "team").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(length)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

SUnion() 并集;SDiff() 差集;SInter() 交集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
rdb.SAdd(ctx, "setA", "a", "b", "c", "d")
rdb.SAdd(ctx, "setB", "a", "d", "e", "f")

//并集
union, err := rdb.SUnion(ctx, "setA", "setB").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(union) // [c e f b d a]

// 差集
diff, err := rdb.SDiff(ctx, "setA", "setB").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(diff) // [c b]

// 交集
inter, err := rdb.SInter(ctx, "setA", "setB").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(inter) // [d a]
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

有序集合(zset)类型

Redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数score。redis正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但**分数(score)**却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。

ZAdd() 添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
"context"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
rdb.ZAdd(ctx, "zSet", &redis.Z{
Score: 0,
Member: "hello",
})
rdb.ZAdd(ctx, "zSet", &redis.Z{
Score: 2.3,
Member: "world",
})
rdb.ZAdd(ctx, "zSet", &redis.Z{
Score: 3.14,
Member: "pai",
})
rdb.ZAdd(ctx, "zSet", &redis.Z{
Score: -12.3,
Member: "张三",
})
rdb.ZAdd(ctx, "zSet", &redis.Z{
Score: 10,
Member: "tom",
})
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

添加后结果如下:

ZIncrBy() 增加元素分值

函数签名:

1
func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
  • increment参数可以为负数,表示减少score
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"context"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
rdb.ZIncrBy(ctx, "zSet", -3.14, "pai")
rdb.ZIncrBy(ctx, "zSet", 123, "hello")
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

修改前后:

ZRange()&ZRevRange() 获取根据score排序后的数据段

ZRange()&ZRevRange():返回根据分值过滤之后的列表,需要提供分值区间。

  • ZRange():结果按score升序排序(自然顺序)
  • ZRevRangeByScore():结果按score降序排序

使用方法是完全一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.ZRangeByScore(ctx, "zSet", &redis.ZRangeBy{
Min: "2",
Max: "20",
Offset: 0,
Count: 0,
}).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(result)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

关于OffsetCount,这是分页查询常见的了。当Count为0时,表示查询全部。

ZCard() 获取元素个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
count, err := rdb.ZCard(ctx, "zSet").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(count)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

ZCount() 获取区间内元素个数

函数签名:

1
func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd

ZCount():获取分值在[mim, max]的元素的数量(左闭右闭)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
count, err := rdb.ZCount(ctx, "zSet", "2", "20").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(count)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

ZScore() 获取元素的score

ZScore():获取元素的分值score。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
score, err := rdb.ZScore(ctx, "zSet", "hello").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(score)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

ZRank()&ZRevRank() 获取某个元素在集合中的排名

ZRank()&ZRevRank() :获取某个元素在集合中的排名。

  • ZRank():返回元素在集合中的升序排名情况,从0开始
  • ZRevRank():返回元素在集合中的降序排名情况,从0开始(与ZRank()正好相反,类似倒数第几,因为是从0开始所以最末尾的元素是倒数第0)

使用方法是完全一样的。效果很简单自己玩一玩就明白函数是什么意思了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
result, err := rdb.ZRank(ctx, "zSet", "tom").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(result)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

ZRem() 删除元素

ZRem():通过元素的值来删除元素。(注意是元素值而不是score)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
val, err := rdb.ZRem(ctx, "zSet", "张三").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

ZRemRangeByRank() 根据排名删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
// 按照升序排序删除第1个和第2个元素
val, err := rdb.ZRemRangeByRank(ctx, "zSet", 0, 1).Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}

ZRemRangeByScore() 根据分值区间删除

函数签名:

1
func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd

ZRemRangeByScore():删除分值区间在[min,max]的所有元素(左闭右闭)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"
"log"

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

var ctx = context.Background()
var rdb *redis.Client

func main() {
// 删除分值区间在[100,123]之间的所有元素
val, err := rdb.ZRemRangeByScore(ctx, "zSet", "100", "123").Result()
if err != nil {
log.Fatalln(err)
}
fmt.Println(val)
}

func init() {
rdb = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 10, // 默认数据库(不指定默认是0)
})
}