🎈个人公众号:🎈 :✨✨✨ 可为编程✨ 🍟🍟
🔑个人信条:🔑 知足知不足 有为有不为 为与不为皆为可为🌵
🍉本篇简介:🍉 本篇记录Redis五种数据类型及命令操作,如有出入还望指正。
Redis哈希(Hash)
简介
Redis中的Hash是一个键值对集合。Redis Hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似于java里面的Map<String,Object>集合一样,如果内存足够大的话,一个Redis的Hash结构可以存储2的32次幂-1个键值对,相当于40亿条数据,其实Hash类型的vlue在Redis中存储时其存储的还是String类型的字符串。下面就针对Hash的一些命令进行实战化演练。
常用命令
hset:设置多个field的值
hset key field value [field value ...]
将哈希表
key
中的域field
的值设为value
。如果
key
不存在,一个新的哈希表被创建并进行 hset 操作。如果域
field
已经存在于哈希表中,旧值将被覆盖。返回值:
如果
field
是哈希表中的一个新建域,并且值设置成功,返回1
。如果哈希表中域
field
已经存在且旧值已被新值覆盖,返回0
。
示例
hget:获取指定filed的值
hget key field
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 18#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hget user name #获取user中的name
"kewei"
hgetall:返回hash表所有的域和值
hgetall key
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 18#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hgetall user #获取user所有信息
1)"name"
2)"kewei"
3)"age"
4)"18"
hmset:和hset类似(已弃用)
hmset key field value [field value ...]
hexists:判断给定的field是否存在,1:存在,0:不存在
hexists key field
查看哈希表
key
中,给定域field
是否存在。返回值:
如果哈希表含有给定域,返回
1
。如果哈希表不含有给定域,或
key
不存在,返回0
。关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hexists user name #user中存在name域
(integer)1
127.0.0.1:6379> hexists user address #user中不存在address域,返回0
(integer)0
127.0.0.1:6379> hexists user1 address #user1这个key不存在,返回0
(integer)0
hkeys:列出所有的filed
hkeys key
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hkeys user #获取user中的所有filed
1)"name"
2)"age"
hvals:列出所有的value
hvals key
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hvals user #获取user中的所有filed的值列表
1)"kewei"
2)"30"
hlen:返回filed的数量
HLEN key
返回哈希表
key
中域的数量。返回值:
哈希表中域的数量。
当
key
不存在时,返回0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hlen user
(integer)2
hincrby:filed的值加上指定的增量
hincrby key field increment
为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。如果域 field 不存在,那么在执行命令前,域的值被初始化为 0。如果对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误,因此只有当值为整型时才会起作用。
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
返回值:
执行 hincrby 命令之后,哈希表
key
中域field
的值。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset siteInfo site kewei pv 1000#hash表siteInfo中有2个域:{site:"kewei",pv:1000}
(integer)2
127.0.0.1:6379> hget siteInfo pv #获取siteInfo中pv的值
"1000"
127.0.0.1:6379> hincrby siteInfo pv 10#siteInfo中的pv值增加10
(integer)1010
127.0.0.1:6379> hget siteInfo pv #获取siteInfo中的pv
"1010"
127.0.0.1:6379> hincrby siteInfo uv 500#siteInfo中的uv值增加500,uv这个域不存在,则会先添加,然后再执行hincrby
(integer)500
hsetnx:当filed不存在的时候,设置filed的值
hsetnx key field value
将哈希表
key
中的域field
的值设置为value
,当且仅当域field
不存在。若域
field
已经存在,该操作无效。如果
key
不存在,一个新哈希表被创建并执行 hsetnx 命令。返回值:
设置成功,返回
1
。如果给定域已经存在且没有操作被执行,返回
0
。关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#创建user,包含2个域:name、age
(integer)2
127.0.0.1:6379> hsetnx user name tom #name已存在,设置失败,返回0
(integer)0
127.0.0.1:6379> hget user name #name依旧是kewei
"kewei"
127.0.0.1:6379> hsetnx user address shanghai #address不存在,设置成功
(integer)1
127.0.0.1:6379> hget user address #输出address的值
"shanghai"
数据结构
Hash类型对应的数据结构是2种:一种是ziplist(压缩列表),第二种时hashtable(哈希表)。当存储的数据不多时采用ziplist,当超过配置文件中的阈值时,采用hashtable进行存储。当field-vaklue长度较短个数较少时,使用ziplist,否则使用hashtable。
Redis有序集合(zset/sortedset)
简介
Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个分数(score),这个分数(score)被用来按照从最低分到最高分的方式排序集合中的成员。ZSet 有两种不同的实现,分别是ziplist(压缩表)和skiplist(跳表)。具体使用哪种结构进行存储,规则如下:
ziplist
满足以下两个条件:
-
[value,score] 键值对数量少于128个
-
每个元素的长度小于 64 字节
skiplist
:不满足以上两个条件时使用跳表、组合了 hash 和 skiplist
-
hash 用来存储 value 到 score 的映射,这样就可以在 O(1) 时间内找到 value 对应的分数。
-
skiplist 按照从小到大的顺序存储分数。
-
skiplist 每个元素的值都是 [value,score] 对。
因为元素是有序的,所以可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。
常用命令
zadd:添加元素
zadd <key><score1><member1><score2><member2>...
将一个或多个
member
元素及其score
值加入到有序集key
当中。如果某个
member
已经是有序集的成员,那么更新这个member
的score
值,并通过重新插入这个member
元素,来保证该member
在正确的位置上。
score
值可以是整数值或双精度浮点数。如果
key
不存在,则创建一个空的有序集并执行 zadd 操作。当
key
存在但不是有序集类型时,返回一个错误。返回值:
被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
zrange:score升序,获取指定索引范围的元素
zrange key start top [withscores]
返回存储在有序集合
key
中的指定范围的元素。返回的元素可以认为是按score从最低到最高排列,如果得分相同,将按字典排序。下标参数
start
和stop
都以0
为底,也就是说,以0
表示有序集第一个成员,以1
表示有序集第二个成员,以此类推。你也可以使用负数下标,以
-1
表示最后一个成员,-2
表示倒数第二个成员,以此类推。zrange key 0 -1:可以获取所有元素
withscores:让成员和它的
score
值一并返回,返回列表以value1,score1, ..., valueN,scoreN
的格式表示可用版本:
>= 1.2.0
时间复杂度:
O(log(N)+M),
N
为有序集的基数,而M
为结果集的基数。返回值:
指定区间内,带有
score
值(可选)的有序集成员的列表。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrange topn 0 -1#按score升序,返回topn中所有元素的值
1)"php"
2)"js"
3)"c"
4)"c++"
5)"java"
127.0.0.1:6379> zrange topn 0 -1 withscores #按score升序,返回所有元素的值以及score
1)"php"
2)"50"
3)"js"
4)"70"
5)"c"
6)"80"
7)"c++"
8)"90"
9)"java"
10)"100"
127.0.0.1:6379> zrange topn 24#返回索引范围[2,4]内的3个元素
1)"c"
2)"c++"
3)"java"
zrevrange:score降序,获取指定索引范围的元素
zrevrange key start stop [WITHSCORES]
返回存储在有序集合
key
中的指定范围的元素。返回的元素可以认为是按score最高到最低排列, 如果得分相同,将按字典排序。下标参数
start
和stop
都以0
为底,也就是说,以0
表示有序集第一个成员,以1
表示有序集第二个成员,以此类推。你也可以使用负数下标,以
-1
表示最后一个成员,-2
表示倒数第二个成员,以此类推。withscores:让成员和它的
score
值一并返回,返回列表以value1,score1, ..., valueN,scoreN
的格式表示
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrevrange topn 0-1#按照score降序获取所有元素
1)"java"
2)"c++"
3)"c"
4)"js"
5)"php"
127.0.0.1:6379> zrevrange topn 02#按照score降序获取前3名
1)"java"
2)"c++"
3)"c"
zrangebyscore:按照score升序,返回指定score范围内的数据
zrangebyscore key min max [WITHSCORES][LIMIT offset count]
返回有序集
key
中,所有score
值介于min
和max
之间(包括等于min
或max
)的成员。有序集成员按score
值递增(从小到大)次序排列。具有相同
score
值的成员按字典序来排列(该属性是有序集提供的,不需要额外的计算)。可选的
LIMIT
参数指定返回结果的数量及区间(就像SQL中的SELECT LIMIT offset, count
),注意当offset
很大时,定位offset
的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。可选的
WITHSCORES
参数决定结果集是单单返回有序集的成员,还是将有序集成员及其score
值一起返回。关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrangebyscore topn 7090#score升序,获取score位于[70,90]区间中的元素值
1)"js"
2)"c"
3)"c++"
127.0.0.1:6379> zrangebyscore topn 7090 withscores #score升序,获取score位于[70,90]区间中的元素值及score
1)"js"
2)"70"
3)"c"
4)"80"
5)"c++"
6)"90"
127.0.0.1:6379> zrangebyscore topn 7090 withscores limit 12#相当于:select value,score from topn集合 where score>=70 and score<=90 order by score asc limit 1,2
1)"c"
2)"80"
3)"c++"
4)"90"
zrevrangebyscore:按照score降序,返回指定score范围内的数据
zrevrangebyscore key max min [WITHSCORES][LIMIT offset count]
返回有序集
key
中,score
值介于max
和min
之间(默认包括等于max
或min
)的所有的成员。有序集成员按score
值递减(从大到小)的次序排列。具有相同
score
值的成员按字典序的逆序排列。除了成员按
score
值递减的次序排列这一点外, zrevrangebyscore 命令的其他方面和 zrangebyscore 命令一样。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrevrangebyscore topn 10090#score降序,获取score位于[70,90]区间中的元素值
1)"java"
2)"c++"
127.0.0.1:6379> zrevrangebyscore topn 10090 withscores #score降序,获取score位于[70,90]区间中的元素值及score
1)"java"
2)"100"
3)"c++"
4)"90"
zincrby:为指定元素的score加上指定的增量
zincrby key increment member
为有序集
key
的成员member
的score
值加上增量increment
。可以通过传递一个负数值
increment
,让score
减去相应的值,比如ZINCRBY key -5 member
,就是让member
的score
值减去5
。当
key
不存在,或member
不是key
的成员时,ZINCRBY key increment member
等同于ZADD key increment member
。当
key
不是有序集类型时,返回一个错误。
score
值可以是整数值或双精度浮点数。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++#集合topx中添加3个元素:java、c、c++,对应的score分别是:90、70、80
(integer)3
127.0.0.1:6379> zrevrange topx 0-1 withscores #输出集合topx中的元素,包含score
1)"java"
2)"90"
3)"c++"
4)"80"
5)"c"
6)"70"
127.0.0.1:6379> zincrby topx 5 java #对topx中的元素java的score加5,变成95了
"95"
127.0.0.1:6379> zrevrange topx 0-1 withscores # 输出集合元素,注意java的score是95了
1)"java"
2)"95"
3)"c++"
4)"80"
5)"c"
6)"70"
zrem:删除集合中多个元素
zrem key member [member ...]
移除有序集
key
中的一个或多个成员,不存在的成员将被忽略。当
key
存在但不是有序集类型时,返回一个错误。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++#集合topx中添加3个元素:java、c、c++,对应的score分别是:90、70、80
(integer)3
127.0.0.1:6379> zrange topx 0-1#输出集合topx中所有元素
1)"c"
2)"c++"
3)"java"
127.0.0.1:6379> zrem topx c c++#删除集合topx中的2个元素:c、c++
(integer)2
127.0.0.1:6379> zrange topx 0-1#输出集合topx中所有元素
1)"java"
zremrangebyrank:根据索引范围删除元素
zremrangebyrank key start stop
移除有序集
key
中,指定排名(rank)区间内的所有成员。区间分别以下标参数
start
和stop
指出,包含start
和stop
在内。下标参数
start
和stop
都以0
为底,也就是说,以0
表示有序集第一个成员,以1
表示有序集第二个成员,以此类推。你也可以使用负数下标,以
-1
表示最后一个成员,-2
表示倒数第二个成员,以此类推。关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++#集合topx中添加3个元素:java、c、c++,对应的score分别是:90、70、80
(integer)3
127.0.0.1:6379> zrange topx 0-1#输出集合topx中所有元素
1)"c"
2)"c++"
3)"java"
127.0.0.1:6379> zremrangebyrank topx 01#删除索引范围[0,1]的数据
(integer)2
127.0.0.1:6379> zrange topx 0-1#输出topx中所有元素
1)"java"
zremrangebyscore:根据score的范围删除元素
zremrangebyscore key min max
移除有序集
key
中,所有score
值介于min
和max
之间(包括等于min
或max
)的成员
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrange topx 0 -1 withscores #输出topx中所有元素值、score
1)"php"
2)"50"
3)"c"
4)"70"
5)"c++"
6)"80"
7)"java"
8)"90"
127.0.0.1:6379> zremrangebyscore topx 7080#删除score位于[70,80]区间的元素
(integer)2
127.0.0.1:6379> zrange topx 0 -1 withscores #输出剩下的元素
1)"php"
2)"50"
3)"java"
4)"90"
zcount:统计指定score范围内元素的个数
zcount key min max
返回有序集
key
中,score
值在min
和max
之间(默认包括score
值等于min
或max
)的成员的数量
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zcount topx 80100#统计score位于[80,100]区间中的元素个数
(integer)2
zrank:按照score升序,返回某个元素在集合中的排名
zrank key member
返回有序集
key
中成员member
的排名。其中有序集成员按score
值递增(从小到大)顺序排列。排名以
0
为底,也就是说,score
值最小的成员排名为0
。关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrank topx c #获取元素c的排名,返回1表示排名第2
(integer)1
127.0.0.1:6379> zrange topx 0-1#输出集合中所有元素,看一下c的位置确实是2
1)"php"
2)"c"
3)"c++"
4)"java"
zrevrank:按照score降序,返回某个元素在集合中的排名
返回有序集
key
中成员member
的排名。其中有序集成员按score
值递减(从大到小)排序。排名以
0
为底,也就是说,score
值最大的成员排名为0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrange topx 0-1
1)"php"
2)"c"
3)"c++"
4)"java"
127.0.0.1:6379> zrevrank topx java #score降序,得到java的排名,排在第1位
(integer)0
zscore:返回集合中指定元素的score
zscore key member
返回有序集
key
中,成员member
的score
值。如果
member
元素不是有序集key
的成员,或key
不存在,返回nil
。
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrange topx 0-1#输出topx集合所有元素
1)"php"
2)"c"
3)"c++"
4)"java"
127.0.0.1:6379> zscore topx java #获取集合topx中java的score
"90"
数据结构
SortedSet(zset)是redis提供的一个非常特别的数据结构,内部使用到了2种数据结构。
1、hash表
类似于java中的Map<String,score>,key为集合中的元素,value为元素对应的score,可以用来快速定位元素定义的score,时间复杂度为O(1)。
2、跳表
跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入、删除、查找的复杂度均为O(logN)。类似java中的ConcurrentSkipListSet,根据score的值排序后生成的一个跳表,可以快速按照位置的顺序或者score的顺序查询元素。
这里我们来看一下跳表的原理:
首先从考虑一个有序表开始:
从该有序表中搜索元素 < 23, 43, 59 > ,需要比较的次数分别为 < 2, 4, 6 >,总共比较的次数为 2 + 4 + 6 = 12 次。有没有优化的算法吗? 链表是有序的,但不能使用二分查找。类似二叉搜索树,我们把一些节点提取出来,作为索引。得到如下结构:
这里我们把 < 14, 34, 50, 72 > 提取出来作为一级索引,这样搜索的时候就可以减少比较次数了。我们还可以再从一级索引提取一些元素出来,作为二级索引,变成如下结构:
这里元素不多,体现不出优势,如果元素足够多,这种索引结构就能体现出优势来了。
Redis概述和安装
Redis五种数据类型及命令操作(一)
IOC容器创建bean实例的4种方式
由表及里分析Spring-IOC容器始末
Spring中的核心概念
关于高并发你必须知道的几个概念
线程的创建方式对比与线程池相关原理剖析