1.1.1. 01.基础数据结构


Redis 有五种数据结构,分别是 String(字符串)、List(列表〉、Hash (字典〉 、 Set(集合)和 Zset(有序集合〉。

1.String 字符串

Redis 的字符串是动态字符串,是可以修改的字符串,采用预分配冗余空间的形式来减少内存的频繁分配。

  • 当字符串小于 1M 时,按原来的的空间加倍来扩容。如当前空间 16kb,扩容后是 32kb。
  • 当字符串大于 1M 时,只会比当前空间多加 1M 来扩容。如当前空间 2M,扩容后是 3M。
  • Redis 的 String 类型最大长度是 512MB。

String 的用途

  • 缓存用户信息,通过对 json 序列化,将用户所有信息存储到 String。同样以 json 反序列化来取出用户数据。
# 设置键值对, set [key] [value]
> set name codehole 
OK

# 获取某个键, get [key]
> get name 
"codehole"

# 查询某个键是否存在, exists [key]
> exists name
(integer) 1

# 删除某个键 ,del [key]
> del name
(integer) 1
> get name  # 再次查询则已经被删除
(nil)

批量设置键值对,可以节省网络耗时开销

# 批量赋值, mset [key1] [value1] [key2] [value2] ....
> mset name1 boy name2 girl name3 unknown
OK

# 批量查询,mget [key1] [key2] ...
> mget name1 name2 name3
1) "boy"
2) "girl"
3) "unknown"

过期和 set 的扩展命令

# 给某个键添加过期时间, expire [key] [secend]
> set name codehole

> get name ” codehole "

> expire name 5
...  # wait for 5s

> get name # 已经被删除了
(nil)

# 当对一个有 ttl 的 key 进行重新赋值时,会删除原来的 ttl


# 设置键值对并且设置过期时间, setex [key] [expire] [value]
> setex name 5 codehole  # 5s 后过期,等价于 set+expire
> get name
"codehole"
... # wait for 5s
> get name
(nil)


# 设置键值对,若存在则不创建,否则创建。 setnx [key] [value]
> setnx name codehole  # 如果 name 不存在就执行 set 创建
(integer) 1
> get name
"codehole"
> setnx name holycoder
(integer) 0  # 因为 name 已经存在,所以 set 创建不成功
> get name
"codehole"  # 没有改变

计数

> set age 30
OK

# 通过 incr [key], incrby [key] [increment] 来做加法
# 通过 decr [key], decrby [key] [decrement] 来做减法
> incr age
(integer) 31
> incrby age 5
(integer) 36
> incrby age -5
(integer) 31
> decrby age 5
(integer) 26

# 如果 value 是一个整数,那么他的范围是在 signed long 的最大和最小值之间。超过范围则 Redis 报错。
> set codehole 9223372036854775807  # Long.Max
OK
> incr codehole
(error) ERR increment or decrement would overflow

2.List 列表

Redis 的列表是个链表,对于插入和删除操作的时间复杂度是 O(1)。但是索引定位 index 会很慢,时间复杂度为 O(n)。 当列表弹出最后一个元素后,则该数据结构被自动删除,内存释放。

队列

#从 左/右 边压入,lpush/rpush [key] [value1] [value2] [value3]
#从 左/右 边弹出,lpop/rphp [key]

队列:右进左出,先进先出

  • 常用于消息队列和异步逻辑处理,确保元素的访问顺序性
    > rpush books python java golang
    (integer) 3
    > llen books
    (integer) 3
    > lpop books
    "python"
    > lpop books
    "java"
    > lpop books
    "golang"
    > lpop books
    (nil)
    

栈:右进右出

> rpush books python java golang
(integer) 3
> rpop books
"golang"
> rpop books
"java"
> rpop books
"python"
> rpop books
(nil)

慢操作

> rpush books python java golang
(integer) 3

# 查寻元素,从 0 开始,index 可以为负数,-1 表示最后一个。lindex [key] [index] 
> lindex books 1  # O(n) 慎用
"java"
> lrange books 0 -1  # 获取所有元素,O(n) 慎用
1) "python"
2) "java"
3) "golang"

# 截取其中一部分,ltirm [key] [start] [stop]
> ltrim books 1 -1 # O(n) 慎用
OK
> lrange books 0 -1
1) "java"
2) "golang"
> ltrim books 1 0 # 这其实是清空了整个列表,因为区间范围长度为负
OK

# 查看长度, llen [key]
> llen books
(integer) 0

3.Hash 哈希

Hash 在移除最后一个元素后,该数据结构自动被删除,内存被回收。

  • 常用于存储用户信息,它可以单独设置或取出用户数据,与 String 一次性取出用户所有数据相比,节省了网络流量。但是 Hash 结构的存储消耗要高于单个 String。所以要根据实际情况进行权衡。

哈稀图

# 向键中插入单个列,hset [key] [field] [value]
> hset books java "think in java"  # 命令行的字符串如果包含空格,要用引号括起来
(integer) 1
> hset books golang "concurrency in go"
(integer) 1
> hset books python "python cookbook"
(integer) 1

# 获取该键所有列,hgetall [key]
> hgetall books  # entries(),key 和 value 间隔出现
1) "java"
2) "think in java"
3) "golang"
4) "concurrency in go"
5) "python"
6) "python cookbook"

# 查看该键长度,hlen [key]
> hlen books
(integer) 3

# 查看该键中某列的值,hget [key] [field]
> hget books java
"think in java"

> hset books golang "learning go programming"  # 因为是更新操作,所以返回 0,但是更新成功
(integer) 0
> hget books golang
"learning go programming"

# 批量设置, hmset [key] [field1] [value1] [field2] [value2] ...
> hmset books java "effective java" python "learning python" golang "modern golang programming"  # 批量 set
OK

对单个 key 进行操作,与 String 的 incrby 用法一样。

# 老钱又老了一岁
> hincrby user-laoqian age 1
(integer) 30

4.Set 集合

Redis 中的 set 是一个无需集合,其内部是「唯一」且「无序」的。

  • 当集合中最后一个元素被移除之后, 数据结构被自动删除, 内存被回收。
  • 可以用作存储活动中奖用户的 id。因为有去重功能,可以保证一个用户不会中奖两次。

集合

# 添加一个或多个元素到集合,sadd [key] [value1] [value2]...
> sadd books python
(integer) 1
> sadd books python  #  重复,则不添加
(integer) 0
> sadd books java golang
(integer) 2

# 查看一个集合,smembers [key]
> smembers books  # 注意顺序,和插入的并不一致,因为 set 是无序的
1) "java"
2) "python"
3) "golang"

# 判断一个元素是否是集合的元素,sismember [key] [value]
> sismember books java  # 查询某个 value 是否存在,相当于 contains(o)
(integer) 1
> sismember books rust
(integer) 0

# 查询一个集合有多少个元素, scard [key]
> scard books  # 获取长度相当于 count()
(integer) 3

# 弹出一个集合元素, spop [key]
> spop books  # 弹出一个
"java"

5.Zset 有序集合

同样是一个集合,但集合中每个元素多了一个 score,代表这个元素在集合中的权重。

  • Zset 可以用来记录粉丝/点赞列表,value 为 用户 id,score 为关注/点赞时间。
  • Zset 也可以存储学生成绩,value 值是学生的 ID,score 是他的考试成绩。我们可以对成绩按分数进行排序就可以得到他的名次。

有序集合

# 向有序集合中添加一个元素 zadd [key] [score] [value]
> zadd books 9.0 "think in java"
(integer) 1
> zadd books 8.9 "java concurrency"
(integer) 1
> zadd books 8.6 "java cookbook"
(integer) 1


# 顺序查询,zrange [key] [start] [stop]
> zrange books 0 -1  # 按 score 排序列出,参数区间为排名范围
1) "java cookbook"
2) "java concurrency"
3) "think in java"

# 逆序查询,z revrange [key] [start] [stop]
> zrevrange books 0 -1  # 按 score 逆序列出,参数区间为排名范围
5) "think in java"
6) "java concurrency"
7) "java cookbook"

# 查看集合中元素个数,zcard [key]
> zcard books  # 相当于 count()
(integer) 3
> zscore books "java concurrency"  # 获取指定 value 的 score
"8.9000000000000004"  # 内部 score 使用 double 类型进行存储,所以存在小数点精度问题


# 查询某个元素在集合中的排名,zrank [key] [value]
> zrank books "java concurrency"  # 排名
(integer) 1

# 查询某个 score 段的元素,zrangebyscore [key] [range_start] [range_end]
> zrangebyscore books 0 8.91  # 根据分值区间遍历 zset
1) "java cookbook"
2) "java concurrency"
> zrangebyscore books -inf 8.91 withscores # 根据分值区间 (-, 8.91] 遍历 zset,同时返回分值。inf 代表 infinite,无穷大的意思。
1) "java cookbook"
2) "8.5999999999999996"
3) "java concurrency"
4) "8.9000000000000004"

# 删除某个元素,zrem [key] [value]
> zrem books "java concurrency"  # 删除 value
(integer) 1
> zrange books 0 -1
1) "java cookbook"
2) "think in java"

6.容器型数据结构的通用规则

list/set/hash/zset 这四种数据结构是容器型数据结构,它们共享下面两条通用规则:

  • create if not exists 如果容器不存在,则创建一个,再进行操作。如 hset 时没有 hash 容器,先创建一个容器,再进行插入。
  • drop if no elements 如果一个容器没有任何元素了,则删除容器。如 lpop 弹出最后一个元素,则删除该队列。

7.过期时间

Redis 所有的数据结构都可以设置过期时间,时间到了,Redis 会自动删除相应的对象。需要注意的是过期是以对象为单位,比如一个 hash 结构的过期是整个 hash 对象的过期,而不是其中的某个子 key。

  • 如果一个字符串设置了时间,然后用 set 方法修改了它,那么它的过期时间则会消失。
127.0.0.1:6379> set codehole yoyo
OK

# 所有容器都支持这个语法 , expire [key] [secend]
127.0.0.1:6379> expire codehole 600
(integer) 1
127.0.0.1:6379> ttl codehole
(integer) 597
127.0.0.1:6379> set codehole yoyo
OK
127.0.0.1:6379> ttl codehole
(integer) -1
Copyright © Kagami丶 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-12-10 21:45:40

results matching ""

    No results matching ""