五种基础数据结构: string(字符串)、list(列表)、set(集合)、hash(集合)和set(有序集合)

使用命令redis-cli即可连接

使用go语言代码连接redis:

import (
	"github.com/go-redis/redis"
)

var c *redis.Client

func main() {
	c = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})
	s, err := c.Ping().Result()
	if err != nil {
		panic(err)
	}
	println(s)
}

string字符串

redis中最简单的数据结构,redis所有的数据结构都是以唯一的key字符串作为名称,然后通过唯一key值来获取相应的value数据,不同类型的数据结构的差异就在于value结构不同,redis的字符串是动态字符串,是可以修改的字符串,采用预分配冗余空间的方法来减少内存的频繁分配。

批量键值对:

127.0.0.1:6379> set name test
OK
127.0.0.1:6379> get name
"test"
127.0.0.1:6379> set name1 test1
OK
127.0.0.1:6379> set name2 test2
OK
127.0.0.1:6379> set name3 test3
OK
127.0.0.1:6379> mget name1 name2 name3
1) "test1"
2) "test2"
3) "test3"

go示例代码:

err = c.Set("key", "value", 0).Err() // set key value
if err != nil {
    panic(err)
}

val, err := c.Get("key").Result() // get key value
if err != nil {
    panic(err)
}

// mset ....
err = c.MSet("key1", "value1", "key2", "value2", "key3", "value3").Err()
if err != nil {
    panic(err)
}

// mget ....
vals, err := c.MGet("key1", "key2", "key3").Result()
if err != nil {
    panic(err)
}
for _, val := range vals {
    println(val.(string))
}

过期策略,对key设置过期时间,到点自动删除,用于控制缓存失效时间

127.0.0.1:6379> expire name 5
(integer) 1
127.0.0.1:6379> get name
"test"
127.0.0.1:6379> get name
(nil)

go示例代码:

err = c.Expire("key",5).Err()
if err != nil {
    panic(err)
}

计数,value是一个整数,可以对其进行自增操作,自增有范围,是signed long的最大最小值

127.0.0.1:6379> set age 30
OK
127.0.0.1:6379> incr age
(integer) 31
127.0.0.1:6379> get age
"31"
127.0.0.1:6379> incrby age -10
(integer) 21
127.0.0.1:6379> get age
"21"

go示例代码:

err = c.Set("num", 1, 0).Err()
if err != nil {
    panic(err)
}
val, err := c.Incr("num").Result()
if err != nil {
    panic(err)
}
println(val)

val, err = c.IncrBy("num", 2).Result()
if err != nil {
    panic(err)
}
println(val)

list列表

redis中列表相当于链表,插入和删除操作快,索引定位快,通常作为异步队列来使用

右进右出:栈

127.0.0.1:6379> rpush values python java golang
(integer) 3
127.0.0.1:6379> rpop values
"golang"
127.0.0.1:6379> rpop values
"java"
127.0.0.1:6379> rpop values
"python"

右进左出:队列

127.0.0.1:6379> rpush values python java golang
(integer) 3
127.0.0.1:6379> lpop values
"python"
127.0.0.1:6379> lpop values
"java"
127.0.0.1:6379> lpop values
"golang"

go示例代码:

err = c.LPush("nums", 1, 2, 3, 4, 5, 6).Err() // RPush同理
if err != nil {
    panic(err)
}
val, err := c.RPop("nums").Result() // LPop同理
if err != nil {
    panic(err)
}
println(val)

使用慢操作

lindex,对链表进行遍历,可以为负数,表示倒数

ltrim,使用两个参数定义一个区间,仅保留该区间里的值,以此来实现一个定长的链表

127.0.0.1:6379> rpush values python java golang
(integer) 3
127.0.0.1:6379> lindex values 1
"java"
127.0.0.1:6379> lrange values 0 -1
1) "python"
2) "java"
3) "golang"
127.0.0.1:6379> ltrim values 1 -1
OK
127.0.0.1:6379> lrange values 0 -1
1) "java"
2) "golang"

go示例代码:

n, err := c.LLen("nums").Result() // llen
if err != nil {
    panic(err)
}
println(n)

vals, err := c.LRange("nums", 0, -1).Result() // lrange
if err != nil {
    panic(err)
}
fmt.Printf("%v\n", vals)

dels, err := c.LRem("nums", 1, 2).Result() // 删除2
if err != nil {
    panic(err)
}
println(dels)

val, err := c.LIndex("nums", 4).Result() // 根据索引坐标 查询列中数据
if err != nil {
    panic(err)
}
println(val)

// 在5之前插入4
err = c.LInsert("nums", "before", 5, 4).Err()
if err != nil {
    panic(err)
}

// 在5之后插入4
err = c.LInsert("after", "after", 5, 4).Err()
if err != nil {
    panic(err)
}

Hash字典

redis的字典采用了渐进式rehash,会在rehash时,保留新旧两个hash结构,同时查询两个hash结构,再后续的定时任务中以及hash操作指令中,循序渐进将旧hash的内容一点点迁移到新hash中,搬迁成功后,就完全用新hash代替旧hash

127.0.0.1:6379> hset keys key1 "value1"
(integer) 0
127.0.0.1:6379> hset keys key2 "value2"
(integer) 1
127.0.0.1:6379> hset keys key3 "value3"
(integer) 1
127.0.0.1:6379> hgetall keys
1) "key1"
2) "value1"
3) "key2"
4) "value2"
5) "key3"
6) "value3"
127.0.0.1:6379> hget keys key1
"value1"
127.0.0.1:6379> hget keys key2
"value2"
127.0.0.1:6379> hget keys key3
"value3"

go示例代码:

c.HSet("keys", "key1", "value1")
c.HSet("keys", "key2", "value2")
c.HSet("keys", "key3", "value3")

val, err := c.HGet("keys", "key1").Result()
if err != nil {
    panic(err)
}
println(val)

// 输出
data, err := c.HGetAll("keys").Result()
if err != nil {
    panic(err)
}
for field, val := range data {
    println(field, val)
}

Zset有序集合

是一个set,内部value是唯一的,又给每一个value赋予一个score,代表value的权重,内部排序使用跳表来实现

127.0.0.1:6379> zadd langs 9.0 "java"
(integer) 1
127.0.0.1:6379> zadd langs 8.0 "python"
(integer) 1
127.0.0.1:6379> zadd langs 8.5 "golang"
(integer) 1
127.0.0.1:6379> zrange langs 0 -1
1) "python"
2) "golang"
3) "java"
127.0.0.1:6379> zcard langs
(integer) 3
127.0.0.1:6379> zscore langs "java"
"9"
127.0.0.1:6379> zrangebyscore langs 0 8
1) "python"
127.0.0.1:6379> zrangebyscore langs 0 8 withscores
1) "python"
2) "8"
127.0.0.1:6379> zrem langs "java"
(integer) 1
127.0.0.1:6379> zrange langs 0 -1
1) "python"
2) "golang"

对应go代码:

c.ZAdd("keys", redis.Z{Score: 2.5, Member: "score1"},
    redis.Z{Score: 5, Member: "score2"})

count, err := c.ZCard("keys").Result()
if err != nil {
    panic(err)
}
println(count)

elems, err := c.ZRange("keys", 0, -1).Result()
if err != nil {
    panic(err)
}
for _, elem := range elems {
    fmt.Printf("%v\n", elem)
}

score, err := c.ZScore("keys", "score1").Result()
if err != nil {
    panic(err)
}
println(score)

c.ZRem("keys", "score1")
elems, err = c.ZRange("keys", 0, -1).Result()
if err != nil {
    panic(err)
}
for _, elem := range elems {
    fmt.Printf("%v\n", elem)
}