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 pjjltOK127.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 gongsiOK127.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 gongsiOK127.0.0.1:6379> expire company 10(integer) 1127.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) 0127.0.0.1:6379> get company"gongsi"
批量设置获取值
127.0.0.1:6379> mset name pjjlt age 26 company gongsiOK127.0.0.1:6379> mget name age company1) "pjjlt"2) "26"3) "gongsi"
批量设置应用mset
,批量获取应用mget
。批量设置获取,缩小IO,进步性能,你值得领有。
计数
redis还能够通过自增的形式计数。
127.0.0.1:6379> set key 10OK127.0.0.1:6379> incr key(integer) 11127.0.0.1:6379> incr key(integer) 12# 字符串报错127.0.0.1:6379> set key2 hahaOK127.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 9223372036854775807OK127.0.0.1:6379> incr key3(error) ERR increment or decrement would overflow# key4不存在127.0.0.1:6379> incr key4(integer) 1127.0.0.1:6379> incr key4(integer) 2
能够通过incr
关键字自增,能够看出key自增了两次。不能给字符串自增,那样会报错,例如key2。不能超过long
的范畴,那样也会报错,例如key3。如果初始key不存在,则增从0开始,例如key4。
追加值
127.0.0.1:6379> set name pjOK127.0.0.1:6379> append name jlt(integer) 5127.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) 2127.0.0.1:6379> get name"pj"
获取局部字符串
127.0.0.1:6379> set name pjjltOK127.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 1234567890OK127.0.0.1:6379> object encoding name"int"# 这里设置44个字符127.0.0.1:6379> set name qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwerOK127.0.0.1:6379> object encoding name"embstr"# 这里设置45个字符127.0.0.1:6379> set name qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertOK127.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) 3127.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) 3127.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),先进先出。
常用命令
向队列任意地位退出元素
方才演示的rpush
、lpush
都是从中间退出元素,这两个命令不再演示。还能够应用linsert
在某指定元素前或后插入新的元素。
127.0.0.1:6379> rpush books python java golong(integer) 3# 在java后面插入 ruby127.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 -11) "python"2) "ruby"3) "java"4) "c#"5) "golong"
依据下面在java
前后插入了ruby
和c#
查找元素
127.0.0.1:6379> lrange books 0 -11) "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
能够遍历列表,参数为start
,end
。这里0 -1,是指从第一个到最初一个,即遍历列表。lindex
查找指定地位的元素,参数是下标值。这个命令是慢查问,须要遍历链表。llen
能够查看列表元素个数。
删除数据
方才演示的rpop
、lpop
能够弹出一个元素,不再演示。
能够应用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) 7127.0.0.1:6379> lrem chae 3 a(integer) 0127.0.0.1:6379> lrem char 3 a(integer) 3127.0.0.1:6379> lrange char 0 -11) "b"2) "b"3) "a"4) "c"# 从右删除 3 个a元素127.0.0.1:6379> rpush char1 a a b b a a c (integer) 7127.0.0.1:6379> lrem char1 -3 a(integer) 3127.0.0.1:6379> lrange char1 0 -11) "a"2) "b"3) "b"4) "c"# 删除所有 a 元素127.0.0.1:6379> rpush char2 a a b b a a c(integer) 7127.0.0.1:6379> lrem char2 0 a(integer) 4127.0.0.1:6379> lrange char2 0 -11) "b"2) "b"3) "c"
还能够应用ltrim
截取一部分数据,删除其余数据
127.0.0.1:6379> rpush char3 a b c d e f g(integer) 7127.0.0.1:6379> ltrim char3 1 3OK127.0.0.1:6379> lrange char3 0 -11) "b"2) "c"3) "d"
批改
127.0.0.1:6379> lrange books 0 -11) "python"2) "ruby"3) "java"4) "c#"5) "golong"127.0.0.1:6379> lset books 2 javaScriptOK127.0.0.1:6379> lrange books 0 -11) "python"2) "ruby"3) "javaScript"4) "c#"5) "golong"
能够用lset
更改某个地位上的元素,这也是个慢查问,工夫复杂度为O(n)。
阻塞操作
blpop
和brpop
在lpop
和rpop
根底上减少了阻塞工夫,如果间接获取,发现列表中没有数据,那么会阻塞期待一段时间,如果该段时间内还是无奈失去数据,就返回期待时长。若设置的工夫是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 201) "books"2) "java"(4.61s)# 这里须要在终端1 执行blpop后插入一条数据127.0.0.1:6379> blpop books 01) "books"2) "python"(9.66s)# 除此之外,还能够同时阻塞多个队列,先有数据的那个弹出127.0.0.1:6379> blpop books schools 01) "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) 1127.0.0.1:6379> hset user age 26(integer) 1127.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 shijiazhuangOK127.0.0.1:6379> hmget user name age1) "pjjlt"2) "26"
判断filed是否存在
127.0.0.1:6379> hexists user name(integer) 1
获取所有filed或者value
127.0.0.1:6379> hkeys user1) "name"2) "age"3) "city"127.0.0.1:6379> hvals user1) "pjjlt"2) "26"
获取所有filed和value
127.0.0.1:6379> hgetall user1) "name"2) "pjjlt"3) "age"4) "26"5) "city"6) "shijiazhuang"
自增
127.0.0.1:6379> hincrby user age -8(integer) 18127.0.0.1:6379> hset user scroe 99.6(integer) 1127.0.0.1:6379> hincrbyfloat user scroe 0.4"100"
hincrby
和hincrbyfloat
别离减少或者缩小整型与浮点型。
计算值的长度
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
很适宜缓存对象,比方商城零碎能够寄存商品,hash
key为商品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) 3127.0.0.1:6379> scard books(integer) 4
判断元素是否在汇合中
127.0.0.1:6379> sismember books java(integer) 1127.0.0.1:6379> sismember books c(integer) 0
随机返回肯定数量的元素
127.0.0.1:6379> srandmember books 21) "java"2) "ruby"127.0.0.1:6379> srandmember books 21) "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 books1) "c#"2) "java"3) "python"
计算并查集
127.0.0.1:6379> sadd set1 a b c d e(integer) 5127.0.0.1:6379> sadd set2 d e f g(integer) 4# 计算两个汇合交加127.0.0.1:6379> sinter set1 set21) "e"2) "d"# 计算两个汇合并集127.0.0.1:6379> sunion set1 set21) "g"2) "a"3) "d"4) "e"5) "c"6) "f"7) "b"# 计算两个汇合差集127.0.0.1:6379> sdiff set1 set21) "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) 1127.0.0.1:6379> zadd books 8 python(integer) 1127.0.0.1:6379> zadd books 7 golang(integer) 1# 查看肯定范畴内的值127.0.0.1:6379> zrange books 0 -11) "golang"2) "python"3) "java"# 删除某个值127.0.0.1:6379> zrem books golang(integer) 1# 依据score 正序排127.0.0.1:6379> zrange books 0 -11) "python"2) "java"# 依据score 顺叙排127.0.0.1:6379> zrevrange books 0 -11) "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) 0127.0.0.1:6379> zrank books java(integer) 1# 肯定范畴内scor内的元素127.0.0.1:6379> zrangebyscore books 0 8.81) "python"
总结
命令 | 解释 |
---|---|
zadd | 设置值 |
zrange | 查看肯定范畴内的值 |
zrem | 删除某个值 |
zrange | 依据score正序排 |
zrevrange | 依据score顺叙排 |
zcard | 查看元素个数 |
zscore | 查看某元素分值 |
zrank | 正序排名,从0开始 |
zrangebyscore | 肯定范畴内scor内的元素 |
外部编码
zset外部的排序功能是通过「跳跃列表」数据结构来实现的,它的构造十分非凡,也比较复杂。举个例子吧,就如同一个公司,有9个员工,分为3各小组,每个小组算一个小组长(留神小组长还具备员工角色,只不过多了小组长角色)小组长再选出一个技术总监(技术总监同时具备员工、小组长、技术总监角色)
应用场景
适宜排名性质的场景,比方微博热搜,某技术网站热门博客等等。
总结不易,小伙伴给个赞再走吧。