关于redis:那些年我们用过的Redis还记得大明湖畔那些Redis数据吗

redis五种罕用的数据结构为string (字符串)、list (列表)、set (汇合)、hash (哈希) 和 zset (有序汇合)。小白易读,倡议珍藏。

万丈高楼平地起

reids是键值对构造的NoSql数据库,key都是字符串,常说的数据类型不同,说的都是value

redis所有的数据都会有一个dicEntry,泛滥dicEntry组成一个链表。上方那个sds就是key,能够看出是一个字符串。下方那个绿色的redisObject就是value。能够看出图中给的例子就是string类型。redisObject会指向实在的数据(比方图中的字符串“world”)。前面咱们说的数据类型特指value局部。

string (字符串)

Redis 的字符串是动静字符串,是能够批改的字符串。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。一个字符串最大能够接受512M。

罕用指令

设置获取值

127.0.0.1:6379> set name pjjlt
OK
127.0.0.1:6379> get name
"pjjlt"
127.0.0.1:6379> exists name
(integer) 1

设置应用set,获取应用get,查看某key是否存在用exists

设置过期工夫

127.0.0.1:6379> setex company 10  gongsi
OK
127.0.0.1:6379> get company
"gongsi"
127.0.0.1:6379> get company
(nil)

能够在设置值的时候间接指定,keycompany能够存活10秒。此外,也能够将设置值设置过期工夫离开,应用expire

127.0.0.1:6379> set company gongsi
OK
127.0.0.1:6379> expire company 10
(integer) 1
127.0.0.1:6379> get company
"gongsi"
127.0.0.1:6379> get company
(nil)

保障不笼罩value

redis还提供了命令,在设置值的时候,如果发现key已存在,此次设置失败,保障原始value不被笼罩。应用setnx命令。

127.0.0.1:6379> setnx company gongsi
(integer) 1
# 能够看到第二次设置失败,返回值为 0.
127.0.0.1:6379> setnx company haha
(integer) 0
127.0.0.1:6379> get company
"gongsi"

批量设置获取值

127.0.0.1:6379> mset name pjjlt age 26 company gongsi
OK
127.0.0.1:6379> mget name age company
1) "pjjlt"
2) "26"
3) "gongsi"

批量设置应用mset,批量获取应用mget。批量设置获取,缩小IO,进步性能,你值得领有。

计数

redis还能够通过自增的形式计数。

127.0.0.1:6379> set key 10
OK
127.0.0.1:6379> incr key
(integer) 11
127.0.0.1:6379> incr key
(integer) 12
# 字符串报错
127.0.0.1:6379> set key2 haha
OK
127.0.0.1:6379> incr key2
(error) ERR value is not an integer or out of range
# 超出long的范畴
127.0.0.1:6379> set key3 9223372036854775807
OK
127.0.0.1:6379> incr key3
(error) ERR increment or decrement would overflow
# key4不存在
127.0.0.1:6379> incr key4
(integer) 1
127.0.0.1:6379> incr key4
(integer) 2

能够通过incr关键字自增,能够看出key自增了两次。不能给字符串自增,那样会报错,例如key2。不能超过long的范畴,那样也会报错,例如key3。如果初始key不存在,则增从0开始,例如key4。

追加值

127.0.0.1:6379> set name pj
OK
127.0.0.1:6379> append name jlt
(integer) 5
127.0.0.1:6379> get name
"pjjlt"

字符串长度

127.0.0.1:6379> get name
"pjjlt"
127.0.0.1:6379> strlen name
(integer) 5

设置并返回原先值

127.0.0.1:6379> get name
"pjjlt"
127.0.0.1:6379> getset name mj
"pjjlt"
127.0.0.1:6379> get name
"mj"

设置指定地位的字符

127.0.0.1:6379> get name
"mj"
127.0.0.1:6379> setrange name 0 p
(integer) 2
127.0.0.1:6379> get name
"pj"

获取局部字符串

127.0.0.1:6379> set name pjjlt
OK
127.0.0.1:6379> getrange name 0 2
"pjj"

总结

命令 解释
set 设置值
get 获取值
setex 设置值并增加过期工夫
setnx 保障不笼罩value
mset 批量设置值
mget 批量获取值
incr 计数
append 追加值
strlen 字符串长度
getset 设置并返回原先值
setrange 设置指定地位的字符
getrange 获取局部字符串

外部编码

尽管某种数据类型的value名称是统一的,比方都是string,然而依据数据量的大小,会采纳不同的外部编码,这样能够更高效的利用空间嘛。外部编码类型也贮存在redisObject中。利用object encoding key可查看外部编码类型。

int:长整型,超过长整型或者是字符串会降级。

embstr:小于等于44个字节的字符串。笔者用的是redis5.0.9,有人说这个字节范畴是39,亲测是44。查了一下,源码的确改了,当初是44.

raw:大于44个字节的字符串。

127.0.0.1:6379> set name 1234567890
OK
127.0.0.1:6379> object encoding name
"int"
# 这里设置44个字符
127.0.0.1:6379> set name qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwer
OK
127.0.0.1:6379> object encoding name
"embstr"
# 这里设置45个字符
127.0.0.1:6379> set name qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwert
OK
127.0.0.1:6379> object encoding name
"raw"

应用场景

能够用于计数,比方网站访问量。
能够共享Session,比方分布式系统,多个实例验证用户是否登录。
能够限速,比方管制一个ip或者一个用户肯定工夫内拜访次数。

list (列表)

Redis 的列表相当于 Java 语言外面的 LinkedList,留神它是链表而不是数组。这意味着list 的插入和删除操作十分快,工夫复杂度为 O(1),然而索引定位很慢,工夫复杂度为O(n)。list的两端都能够弹入弹出数据,所以能够做队列

栈与队列

栈如同一个死胡同,只有一个进口,后进来的先出,先进来的后出。

127.0.0.1:6379> rpush books python java golong
(integer) 3
127.0.0.1:6379> rpop books
"golong"
127.0.0.1:6379> rpop books
"java"
127.0.0.1:6379> rpop books
"python"
127.0.0.1:6379> rpop books
(nil)

数据从左边进(rpush),左边出(rpop),先进去的最初进去。

队列

队列如同排队打饭的同学们,先进先出。

127.0.0.1:6379> rpush books python java golong 
(integer) 3
127.0.0.1:6379> lpop books
"python"
127.0.0.1:6379> lpop books
"java"
127.0.0.1:6379> lpop books
"golong"
127.0.0.1:6379> lpop books
(nil)

数据从左边进(rpush),右边出(lpop),先进先出。

常用命令

向队列任意地位退出元素

方才演示的rpushlpush都是从中间退出元素,这两个命令不再演示。还能够应用linsert在某指定元素前或后插入新的元素。

127.0.0.1:6379> rpush books python java golong
(integer) 3
# 在java后面插入 ruby
127.0.0.1:6379> linsert books before java ruby
(integer) 4
# 在java前面插入 c#
127.0.0.1:6379> linsert books after java c#
(integer) 5
# 查看所有元素
127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "java"
4) "c#"
5) "golong"

依据下面在java前后插入了rubyc#

查找元素

127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "java"
4) "c#"
5) "golong"
127.0.0.1:6379> lindex books 2
"java"
127.0.0.1:6379> llen books
(integer) 5

指令简略,索性写一块吧。
lrange能够遍历列表,参数为startend。这里0 -1,是指从第一个到最初一个,即遍历列表。
lindex查找指定地位的元素,参数是下标值。这个命令是慢查问,须要遍历链表。
llen能够查看列表元素个数。

删除数据

方才演示的rpoplpop能够弹出一个元素,不再演示。

能够应用lrem 删除多个同一元素
count > 0:从左到右,删除最多 count 个元素。
count < 0:从右到左,删除最多 count 绝对值 个元素。
count = 0,删除所有。

# 从左删除a元素,删除了3个
127.0.0.1:6379> rpush char a a b b a a c 
(integer) 7
127.0.0.1:6379> lrem chae 3 a
(integer) 0
127.0.0.1:6379> lrem char 3 a
(integer) 3
127.0.0.1:6379> lrange char 0 -1
1) "b"
2) "b"
3) "a"
4) "c"
# 从右删除 3 个a元素
127.0.0.1:6379> rpush char1 a a b b a a c 
(integer) 7
127.0.0.1:6379> lrem char1 -3 a
(integer) 3
127.0.0.1:6379> lrange char1 0 -1
1) "a"
2) "b"
3) "b"
4) "c"
# 删除所有 a 元素
127.0.0.1:6379> rpush char2 a a b b a a c
(integer) 7
127.0.0.1:6379> lrem char2 0 a
(integer) 4
127.0.0.1:6379> lrange char2 0 -1
1) "b"
2) "b"
3) "c"

还能够应用ltrim截取一部分数据,删除其余数据

127.0.0.1:6379> rpush char3 a b c d e f g
(integer) 7
127.0.0.1:6379> ltrim char3 1 3
OK
127.0.0.1:6379> lrange char3 0 -1
1) "b"
2) "c"
3) "d"

批改

127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "java"
4) "c#"
5) "golong"
127.0.0.1:6379> lset books 2 javaScript
OK
127.0.0.1:6379> lrange books 0 -1
1) "python"
2) "ruby"
3) "javaScript"
4) "c#"
5) "golong"

能够用lset更改某个地位上的元素,这也是个慢查问,工夫复杂度为O(n)。

阻塞操作

blpopbrpoplpoprpop根底上减少了阻塞工夫,如果间接获取,发现列表中没有数据,那么会阻塞期待一段时间,如果该段时间内还是无奈失去数据,就返回期待时长。若设置的工夫是0的话,即为有限期待。这里须要两个终端做配合。

# 终端1 
127.0.0.1:6379> lpop books
(nil)
127.0.0.1:6379> blpop books 5
(nil)
(5.06s)
# 这里须要在终端1 执行blpop后插入一条数据
127.0.0.1:6379> blpop books 20
1) "books"
2) "java"
(4.61s)
# 这里须要在终端1 执行blpop后插入一条数据
127.0.0.1:6379> blpop books 0
1) "books"
2) "python"
(9.66s)
# 除此之外,还能够同时阻塞多个队列,先有数据的那个弹出
127.0.0.1:6379> blpop books schools 0
1) "schools"
2) "hzsy"
(26.75s)

总结

命令 解释
rpush lpush 弹入数据
rpop lpop 弹出数据
brpop blpop 阻塞弹出数据
linsert 向队列任意地位退出元素
lrange 遍历列表
lindex 查找指定地位上元素
llen 列表长度
lrem 删除多个同一元素
ltrim 截取指定列表
lset 批改列表指定地位元素

外部编码

ziplist:当列表的元素个数小于list-max-ziplist-entries配置(默认 512 个),同时列表中每个元素的值都小于list-max-ziplist-value 配置时(默认 64 字节),Redis 会选用ziplist 来作为 列表 的外部实现来缩小内存的应用。
linkedlist:当列表类型无奈满足ziplist的条件时,Redis会应用linkedlist作为列表的外部实现。

应用场景

能够做或者队列
还能够利用阻塞性能做音讯队列

hash (哈希)

Redis 的字典相当于Java语言外面的HashMap,它是无序字典。外部实现构造上同Java的HashMap也是统一的,同样的数组 + 链表二维构造。扩容rehash的时候,采纳渐进式。在rehash时,保留两个新旧hash构造,查问的时候都查,再依据定时工作,一点点将旧hash上的数据迁徙到新的hash上,迁徙结束,旧hash被删除,并发出内存。咱们默认key为hashKey,filed为小key

常用命令

设置值

127.0.0.1:6379> hset user name pjjlt
(integer) 1
127.0.0.1:6379> hset user age 26
(integer) 1
127.0.0.1:6379> hset user company gongsi
(integer) 1

获取值

127.0.0.1:6379> hget user name
"pjjlt"

删除field

127.0.0.1:6379> hdel user company
(integer) 1

计算field个数

127.0.0.1:6379> hlen user
(integer) 2

批量设置获取值

127.0.0.1:6379> hmset user name pjjlt age 26 city shijiazhuang
OK
127.0.0.1:6379> hmget user name age
1) "pjjlt"
2) "26"

判断filed是否存在

127.0.0.1:6379> hexists user name
(integer) 1

获取所有filed或者value

127.0.0.1:6379> hkeys user
1) "name"
2) "age"
3) "city"
127.0.0.1:6379> hvals user
1) "pjjlt"
2) "26"

获取所有filed和value

127.0.0.1:6379> hgetall user
1) "name"
2) "pjjlt"
3) "age"
4) "26"
5) "city"
6) "shijiazhuang"

自增

127.0.0.1:6379> hincrby user age -8
(integer) 18
127.0.0.1:6379> hset user scroe 99.6
(integer) 1
127.0.0.1:6379> hincrbyfloat user scroe 0.4
"100"

hincrbyhincrbyfloat别离减少或者缩小整型浮点型

计算值的长度

127.0.0.1:6379> hget user name
"pjjlt"
127.0.0.1:6379> hstrlen user name
(integer) 5

总结

命令 解释
hset 设置值
hget 获取值
hdel 删除值
hlen 计算field个数
hmset 批量设置值
hmget 批量获取值
hexists 判断field是否存在
hkeys 获取所有field
hvals 获取所有value
hgetall 获取所有filed和value
hincrby 减少整型数值
hincrbyfloat 减少浮点型数值
hstrlen 计算值的长度

外部编码

ziplist:当列表的元素个数小于list-max-ziplist-entries配置(默认 512 个),同时列表中每个元素的值都小于list-max-ziplist-value 配置时(默认 64 字节),Redis 会选用ziplist 来作为 列表 的外部实现来缩小内存的应用。

hashtable:当哈希类型无奈满足ziplist的条件时,Redis会应用hashtable作为哈希的外部实现,因为此时ziplist的读写效率会降落,而hashtable的读写工夫复杂度为O(1)。

应用场景

hash很适宜缓存对象,比方商城零碎能够寄存商品,hashkey为商品id,field为各种属性,value为数据。当然string也能够寄存商品,只不过它的value,时json串,还须要解析,从代码角度和网络代价来讲都不如hash

set (汇合)

set相当于Java语言外面的 HashSet,它外部的键值对是无序的惟一的。它的外部实现相当于一个非凡的字典,字典中所有的value都是一个值NULL。

常用命令

减少元素

127.0.0.1:6379> sadd books java python python ruby java
(integer) 3

sadd能够增加一个或者多个元素,并且去重。

删除元素

127.0.0.1:6379> srem books python ruby
(integer) 2

srem能够删除一个或者多个元素。

计算元素个数

127.0.0.1:6379> sadd books python ruby c#
(integer) 3
127.0.0.1:6379> scard books
(integer) 4

判断元素是否在汇合中

127.0.0.1:6379> sismember books java
(integer) 1
127.0.0.1:6379> sismember books c
(integer) 0

随机返回肯定数量的元素

127.0.0.1:6379> srandmember books 2
1) "java"
2) "ruby"
127.0.0.1:6379> srandmember books 2
1) "c#"
2) "ruby"

随机弹出一个元素

127.0.0.1:6379> spop books
"ruby"
127.0.0.1:6379> scard books
(integer) 3

获取所有元素

127.0.0.1:6379> smembers books
1) "c#"
2) "java"
3) "python"

计算并查集

127.0.0.1:6379> sadd set1 a b c d e
(integer) 5
127.0.0.1:6379> sadd set2 d e f g
(integer) 4
# 计算两个汇合交加
127.0.0.1:6379> sinter set1 set2
1) "e"
2) "d"
# 计算两个汇合并集
127.0.0.1:6379> sunion set1 set2
1) "g"
2) "a"
3) "d"
4) "e"
5) "c"
6) "f"
7) "b"
# 计算两个汇合差集
127.0.0.1:6379> sdiff set1 set2
1) "c"
2) "b"
3) "a"

总结

命令 解释
sadd 减少元素
srem 删除元素
scard 计算元素个数
sismember 判断元素是否在汇合中
srandmember 随机返回肯定数量的元素
spop 随机弹出一个元素
smembers 获取所有元素
sinter 计算两个汇合交加
sunion 计算两个汇合并集
sdiff 计算两个汇合差集

外部编码

intset:当汇合中的元素都是整数且元素个数小于set-max-intset-entries配置(默认 512 个)时,Redis会选用intset来作为汇合的外部实现,从而缩小内存的应用。

hashtable:当汇合类型无奈满足intset的条件时,Redis会应用hashtable作为汇合的外部实现。

应用场景

利用并查集能够用于查找用户共同爱好。

利用不可重复性,能够用于抽奖,保障每个用户只能中一次奖。

zset(有序汇合)

zset可能是Redis提供的最为特色的数据结构。它相似于Java的SortedSet和HashMap的结合体,一方面它是一个set,保障了外部value的唯一性,另一方面它能够给每个value赋予一个score,代表这个value的排序权重。

常用命令

# 设置值
127.0.0.1:6379> zadd books 9 java
(integer) 1
127.0.0.1:6379> zadd books 8 python
(integer) 1
127.0.0.1:6379> zadd books 7 golang
(integer) 1
# 查看肯定范畴内的值
127.0.0.1:6379> zrange books 0 -1
1) "golang"
2) "python"
3) "java"
# 删除某个值
127.0.0.1:6379> zrem books golang
(integer) 1
# 依据score 正序排
127.0.0.1:6379> zrange books 0 -1
1) "python"
2) "java"
# 依据score 顺叙排
127.0.0.1:6379> zrevrange books 0 -1
1) "java"
2) "python"
# 查看元素个数
127.0.0.1:6379> zcard books
(integer) 2
# 查看某元素分值
127.0.0.1:6379> zscore books java
"9"
# 正序排名,从0开始
127.0.0.1:6379> zrank books  python
(integer) 0
127.0.0.1:6379> zrank books java
(integer) 1
# 肯定范畴内scor内的元素
127.0.0.1:6379> zrangebyscore books 0 8.8
1) "python"

总结

命令 解释
zadd 设置值
zrange 查看肯定范畴内的值
zrem 删除某个值
zrange 依据score正序排
zrevrange 依据score顺叙排
zcard 查看元素个数
zscore 查看某元素分值
zrank 正序排名,从0开始
zrangebyscore 肯定范畴内scor内的元素

外部编码

zset外部的排序功能是通过「跳跃列表」数据结构来实现的,它的构造十分非凡,也比较复杂。举个例子吧,就如同一个公司,有9个员工,分为3各小组,每个小组算一个小组长(留神小组长还具备员工角色,只不过多了小组长角色)小组长再选出一个技术总监(技术总监同时具备员工、小组长、技术总监角色)

应用场景

适宜排名性质的场景,比方微博热搜,某技术网站热门博客等等。

总结不易,小伙伴给个赞再走吧。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理