玩玩Redis系列(二)

2021/4/25 19:25:21

本文主要是介绍玩玩Redis系列(二),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

玩玩Redis系列二

  • Redis数据结构&相关命令&使用场景
    • 1 string(字符串)
      • 1.1 数据结构
      • 1.2 对字符串的基本操作
        • 1.2.1 设置和获取键值对
        • 1.2.2 使用 EXISTS 和 DEL 关键字来查询是否存在和删除键值对:
        • 1.2.3 批量设置键值对
        • 1.2.4 过期和 SET 命令扩展
        • 1.2.5 计数
        • 1.2.6 返回原值的 GETSET 命令
        • 1.2.7 命令小结
      • 1.3 使用场景
    • 2 list(列表)
      • 2.1 数据结构
      • 2.2 常用命令
      • 2.3 使用场景
    • 3 hash(字典)
      • 3.1 数据结构
      • 3.2 常用命令
      • 3.3 使用场景
    • 4 set(集合)
      • 4.1 数据结构
      • 4.2 常用命令
      • 4.3 使用场景
    • 5 zset(有序集合)
      • 5.1 数据结构
      • 5.2 常用命令
      • 5.3 使用场景
  • 6 总结

Redis数据结构&相关命令&使用场景

Redis 有 5 种基础数据结构,它们分别是:string(字符串)、list(列表)、hash(字典)、set(集合) 和 zset(有序集合)。这 5 种是 Redis 相关知识中最基础、最重要的部分,下面我们结合源码以及一些实践来给大家分别讲解一下。

数据结构底层实现
string(字符串)字符数组(动态字符串)
list(列表)链表
hash(字典)数组 + 链表
set(集合)hash(字典)字典中所有的 value 都是一个值 NULL
zset(有序集合)跳跃表

1 string(字符串)

1.1 数据结构

Redis 中的字符串是一种 动态字符串,这意味着使用者可以修改,它的底层实现有点类似于 Java 中的 ArrayList,有一个字符数组 Redis规定字符串大小不能超过512M

1.2 对字符串的基本操作

1.2.1 设置和获取键值对

> SET key value
OK
> GET key
"value"

使用 SET 和 GET 来设置和获取字符串值。
值可以是任何种类的字符串(包括二进制数据),例如你可以在一个键下保存一张 .jpeg 图片,只需要注意不要超过 512 MB 的最大限度就好了。

当 key 存在时,SET 命令会覆盖掉你上一次设置的值:

> SET key newValue
OK
> GET key
"newValue"

1.2.2 使用 EXISTS 和 DEL 关键字来查询是否存在和删除键值对:

> EXISTS key
(integer) 1
> DEL key
(integer) 1
> GET key
(nil)

1.2.3 批量设置键值对

> SET key1 value1
OK
> SET key2 value2
OK
> MGET key1 key2 key3    # 返回一个列表
1) "value1"
2) "value2"
3) (nil)
> MSET key1 value1 key2 value2
> MGET key1 key2
1) "value1"
2) "value2"

1.2.4 过期和 SET 命令扩展

可以对 key 设置过期时间,到时间会被自动删除,这个功能常用来控制缓存的失效时间。(过期可以是任意数据结构)

> SET key value1
> GET key
"value1"
> EXPIRE name 5    # 5s 后过期
...                # 等待 5s
> GET key
(nil)

等价于 SET + EXPIRE 的 SETEX 命令:

> SETEX key value1
...                # 等待 5s 后获取
> GET key
(nil)

> SETEX key value1  # 如果 key 不存在则 SET 成功
(integer) 1
> SETEX key value1  # 如果 key 存在则 SET 失败
(integer) 0
> GET key
"value"             # 没有改变 

1.2.5 计数

如果 value 是一个整数,还可以对它使用 INCR 命令进行 原子性 的自增操作,这意味着及时多个客户端对同一个 key 进行操作,也决不会导致竞争的情况:

> SET counter 100
> INCR count
(interger) 101
> INCRBY counter 50
(integer) 151

1.2.6 返回原值的 GETSET 命令

对字符串,还有一个 GETSET 比较让人觉得有意思,它的功能跟它名字一样:为 key 设置一个值并返回原值:

> SET key value
> GETSET key value1
"value"

1.2.7 命令小结

set   [key]  [value]   给指定key设置值(set 可覆盖老的值)

get  [key]   获取指定key 的值

del  [key]   删除指定key

exists  [key]  判断是否存在指定key

mset  [key1]  [value1]  [key2]  [value2] ...... 批量存键值对

mget  [key1]  [key2] ......   批量取key

expire [key]  [time]    给指定key 设置过期时间  单位秒

setex    [key]  [time]  [value]  等价于 set + expire 命令组合

setnx  [key]  [value]   如果key不存在则set 创建,否则返回0

incr   [key]           如果value为整数 可用 incr命令每次自增1

incrby  [key] [number]  使用incrby命令对整数值 进行增加 number

1.3 使用场景

存储key-value键值对,这个比较简单不细说了,一般计数器,图片二进制,html二进制,js二进制等等


2 list(列表)

2.1 数据结构

Redis中的list和Java中的LinkedList很像,底层都是一种链表结构, list的插入和删除操作非常快,时间复杂度为 0(1),不像数组结构插入、删除操作需要移动数据。
像归像,但是redis中的list底层可不是一个双向链表那么简单。
当数据量较少的时候它的底层存储结构为一块连续内存,称之为ziplist(压缩列表),它将所有的元素紧挨着一起存储,分配的是一块连续的内存;当数据量较多的时候将会变成quicklist(快速链表)结构。
可单纯的链表也是有缺陷的,链表的前后指针 prev 和 next 会占用较多的内存,会比较浪费空间,而且会加重内存的碎片化。在redis 3.2之后就都改用ziplist+链表的混合结构,称之为 quicklist(快速链表)。

2.2 常用命令

rpush  [key] [value1] [value2] ......    链表右侧插入

rpop    [key]  移除右侧列表头元素,并返回该元素

lpop   [key]    移除左侧列表头元素,并返回该元素

llen  [key]     返回该列表的元素个数

lrem [key] [count] [value]  删除列表中与value相等的元素,count是删除的个数。 count>0 表示从左侧开始查找,删除count个元素,count<0 表示从右侧开始查找,删除count个相同元素,count=0 表示删除全部相同的元素

(PS:   index 代表元素下标,index 可以为负数, index= 表示倒数第一个元素,同理 index=-2 表示倒数第二 个元素。)

lindex [key] [index]  获取list指定下标的元素 (需要遍历,时间复杂度为O(n))

lrange [key]  [start_index] [end_index]   获取list 区间内的所有元素 (时间复杂度为 O(n))

ltrim  [key]  [start_index] [end_index]   保留区间内的元素,其他元素删除(时间复杂度为 O(n))

2.3 使用场景

由于list它是一个按照插入顺序排序的列表,所以应用场景相对还较多的,例如:

  • 消息队列:lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能
  • 朋友圈的点赞列表、评论列表、排行榜:lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表。

3 hash(字典)

3.1 数据结构

Redis 中的 Hash和 Java的 HashMap 更加相似,都是数组+链表的结构,当发生 hash 碰撞时将会把元素追加到链表上,值得注意的是在 Redis 的 Hash 中 value 只能是字符串.

3.2 常用命令

hset  [key]  [field] [value]    新建字段信息

hget  [key]  [field]    获取字段信息

hdel [key] [field]  删除字段

hlen  [key]   保存的字段个数

hgetall  [key]  获取指定key 字典里的所有字段和值 (字段信息过多,会导致慢查询 慎用:亲身经历 曾经用过这个这个指令导致线上服务故障)

hmset  [key]  [field1] [value1] [field2] [value2] ......   批量创建

hincr  [key] [field]   对字段值自增

hincrby [key] [field] [number] 对字段值增加number

3.3 使用场景

  • 购物车:hset [key] [field] [value] 命令, 可以实现以用户Id,商品Id为field,商品数量为value,恰好构成了购物车的3个要素。
  • 存储对象:hash类型的(key, field, value)的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。

4 set(集合)

4.1 数据结构

Redis 中的 set和Java中的HashSet 有些类似,它内部的键值对是无序的、唯一 的。它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值 NULL。当集合中最后一个元素被移除之后,数据结构被自动删除,内存被回收。

4.2 常用命令

sadd  [key]  [value]  向指定key的set中添加元素

smembers [key]    获取指定key 集合中的所有元素

sismember [key] [value]   判断集合中是否存在某个value

scard [key]    获取集合的长度

spop  [key]   弹出一个元素

srem [key] [value]  删除指定元素

4.3 使用场景

  • 好友、关注、粉丝、感兴趣的人集合:
    • sinter命令可以获得A和B两个用户的共同好友;
    • sismember命令可以判断A是否是B的好友;
    • scard命令可以获取好友数量;
    • 关注时,smove命令可以将B从A的粉丝集合转移到A的好友集合
  • 首页展示随机:美团首页有很多推荐商家,但是并不能全部展示,set类型适合存放所有需要展示的内容,而srandmember命令则可以从中随机获取几个。
  • 存储某活动中中奖的用户ID ,因为有去重功能,可以保证同一个用户不会中奖两次。

5 zset(有序集合)

5.1 数据结构

zset也叫SortedSet一方面它是个 set ,保证了内部 value 的唯一性,另方面它可以给每个 value 赋予一个score,代表这个value的排序权重。它的内部实现用的是一种叫作“跳跃列表”的数据结构。

5.2 常用命令

zadd [key] [score] [value] 向指定key的集合中增加元素

zrange [key] [start_index] [end_index] 获取下标范围内的元素列表,按score 排序输出

zrevrange [key] [start_index] [end_index]  获取范围内的元素列表 ,按score排序 逆序输出

zcard [key]  获取集合列表的元素个数

zrank [key] [value]  获取元素再集合中的排名

zrangebyscore [key] [score1] [score2]  输出score范围内的元素列表

zrem [key] [value]  删除元素

zscore [key] [value] 获取元素的score

5.3 使用场景

  • zset 可以用做排行榜,但是和list不同的是zset它能够实现动态的排序,例如: 可以用来存储粉丝列表,value 值是粉丝的用户 ID,score 是关注时间,我们可以对粉丝列表按关注时间进行排序。

  • zset 还可以用来存储学生的成绩, value 值是学生的 ID, score 是他的考试成绩。 我们对成绩按分数进行排序就可以得到他的名次。

6 总结

Redis包含5中类型数据结构,每种的特点和底层数据结构会让我们在开发使用中,更好的选择,总结比较粗浅,日后在完善补充。



这篇关于玩玩Redis系列(二)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程