Redis进阶
01、Redis进阶:Nosql数据库简介
02、Redis进阶:多种方式安装Redis6.2.2
03、Redis进阶:Redis常用五大数据类型
04、Redis进阶:Redis三种特殊数据类型之Bitmaps、HyperLogLog、Geospatial
05、Redis进阶:Redis持久化规则之RDB及AOF
06、Redis进阶:Redis发布订阅及SpringBoot集成Redis实现发布订阅消息
07、Redis进阶:Redis事务详解
08、Redis进阶:Redis之主从复制详解
09、Redis进阶:Redis之哨兵模式(sentinel)详解
10、Redis进阶:Redis集群搭建
11、Redis进阶:Redis6新特性
12、Redis进阶:SpringBoot集成Redis环境搭建及配置详解
13、Redis进阶:RedisTemplate操作Redis详解之连接Redis及自定义序列化
14、Redis进阶:RedisTemplate操作Redis之API详解
15、Redis进阶:Redis之面试常问缓存穿透+缓存击穿+缓存雪崩
本文档使用 MrDoc 发布
-
+
首页
03、Redis进阶:Redis常用五大数据类型
### 常用命令 ------------ Redis命令十分丰富,包括的命令组有Cluster、Connection、Geo、Hashes、HyperLogLog、Keys、Lists、Pub/Sub、Scripting、Server、Sets、Sorted Sets、Strings、Transactions一共14个redis命令组两百多个redis命令。 ```c # 启动客户端 ./redis-cli # 查看当前库所有key keys * # 查看当前库以KK开头的key keys kk** # 判断某个key是否存在 exists key kk # 查看key是什么类型 type kk # 删除指定的key数据 del key kk # 删除指定的key(s),若key不存在则该key被跳过。但是,相比DEL会产生阻塞,该命令会在另一个线程中回收内存,因此它是非阻塞的。 这也是该命令名字的由来:仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。 unlink key kk # key设置过期时间 expire kk 10 # 查看还有多少秒过期,-1表示永不过期,-2表示已过期 ttl kk # 切换数据库 select 2 # 查看当前数据库的key的数量 dbsize # 清空当前库 flushdb # 清空所有库 flushall ``` ### 五大基本数据类型 ------------ Redis不是简单的键值存储,它实际上是一个支持不同类型值的数据结构服务器。这意味着在传统键值存储中,您将字符串键与字符串值相关联,而在Redis中,该值不仅限于简单的字符串,还可以容纳更复杂的数据结构。以下是Redis支持的所有数据结构的列表: - Binary-safe strings - Lists - Sets - Sorted sets - Hashes - Bit arrays (or simply bitmaps) - HyperLogLogs - Streams ### 一、String字符串 Redis字符串类型是您可以与Redis键关联的最简单的值类型。由于Redis键是字符串,因此当我们也使用字符串类型作为值时,我们会将一个字符串映射到另一个字符串。值可以是每种类型的字符串(包括二进制数据),例如,您可以在值内存储jpeg图像。值不能大于512 MB。 常用命令 **get/set** ```c # 添加键值对,key已存在时,会覆盖 set mykey somevalue # 只有在key不存在时,设置key的值,已存在key时,无法设置 setnx kk vv1sdsds # 查询对应键值 get mykey # 将给定的<value> 追加到原值的末尾 append kk hahaha999 # 获得值的长度 strlen kk # 同时添加多个键值对 mset k1 v1 k2 v2 k3 v3 # 同时获取多个键值 mget k1 k2 # 同时添加多个键值对,当其中某个KEY存在时,则都不会添加 msetnx k4 v4 k3 vv3 # 获得值的范围,从0开始,包含开始结束位置 getrange k1 0 2 # 从1位置开始覆盖k1的值为zxcv setrange k1 1 zxcv # 设置k1的值,并设置10秒后过期 setex k1 10 vv2 # 获取k1原来的值,并设置新的值为vvv1 getset k1 vvv1 ``` **incr/decr** **redis原子性**:Redis采用单线程+多路IO复用技术,所以Redis单个命令的执行都是原子性的,Redis命令的原子性使得我们不用考虑并发问题,可以方便的利用原子性自增操作INCR实现简单计数器功能。 **INCR key**: 对存储在指定key的数值执行原子的加1操作。如果指定的key不存在,那么在执行incr操作之前,会先将它的值设定为0再+1。如果指定的key中存储的值不是字符串类型(fix:)或者存储的字符串类型不能表示为一个整数,那么执行这个命令时服务器会返回一个错误(eq:(error) ERR value is not an integer or out of range)。这个操作仅限于64位的有符号整型数据。 **DECR key**: 对key对应的数字做减1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0再-1。如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。这个操作最大支持在64位有符号的整型数字。 **incrby / decrby key num**:将 key 中储存的数字值增减num。 ```c # +1 incr inkey # -1 decr dekey # +10 incrby inkey 10 # -100 decrby dekey 100 ``` **String数据结构** 不管在什么编程语言、存储引擎中,String都是应用最广泛的,而在不同的编程语言、存储引擎中,String可能有不同的实现,在Redis中,String的底层就是SDS,它的全称是Simple Dynamic String。 ```c struct sdshdr { int len; // 存储字符串的实际长度 int free; // 存储剩余(空闲)的空间 char buf[]; // 存储实际数据 }; ``` **空间预分配**:当对字符串进行拼接操作的时候,Redis会很贴心的分配一定的剩余空间,这块剩余空间现在看起来是有点浪费,但是我们如果继续拼接,这块剩余空间的作用就出来了。 **惰性空间释放**:当我们做了字符串缩减的操作,Redis并不会马上回收空间,因为你可能即将又要做字符串的拼接操作,如果你再次操作,还是没有用到这部分空间,Redis也会去回收这部分空间。 **扩容策略**: 字符串小于1M,采用的是加倍扩容的策略,也就是多分配100%的剩余空间,当大于1M,每次扩容,只会多分配1M的剩余空间。 **最大长度**: Redis 规定字符串的长度不得超过 512M 字节。 ### 二、List列表 Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边),一个列表最多可以包含 (2的32次方 - 1 )个元素 (4294967295, 每个列表超过40亿个元素)。 **常用命令** **LPUSH key value [value …]**: 将所有指定的值插入到存于 key 的列表的头部。如果 key 不存在,那么在进行 push 操作前会创建一个空列表。 如果 key 对应的值不是一个 list 的话,那么会返回一个错误。 **RPUSH key value [value …]**:向存于 key 的列表的尾部插入所有指定的值。 **LPOP key**: 移除并且返回 key 对应的 list 的第一个元素,或者当 key 不存在时返回 nil。 **RPOP key**: 移除并返回存于 key 的 list 的最后一个元素。 **RPOPLPUSH source destination**: 原子性地返回并移除存储在 source 的列表的最后一个元素(列表尾部元素), 并把该元素放入存储在 destination 的列表的第一个元素位置(列表头部) **LRANGE key start stop**: 返回存储在 key 的列表里指定范围内的元素。 start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0(list的表头),第二个元素下标是1,以此类推。 偏移量也可以是负数,表示偏移量是从list尾部开始计数。 例如, -1 表示列表的最后一个元素,-2 是倒数第二个,以此类推。 **LINDEX key index**: 返回列表里的元素的索引 index 存储在 key 里面。 下标是从0开始索引的,所以 0 是表示第一个元素, 1 表示第二个元素,并以此类推。 负数索引用于指定从列表尾部开始索引的元素。在这种方法下,-1 表示最后一个元素,-2 表示倒数第二个元素,并以此往前推。 当key 位置的值不是一个列表的时候,会返回一个error。 **LLEN key** : 返回存储在 key 里的list的长度。 如果 key 不存在,那么就被看作是空list,并且返回长度为 0。 当存储在 key 里的值不是一个list的话,会返回error。 **LINSERT key BEFORE|AFTER pivot value**: 把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。 当key 不存在时,这个list会被看作是空list,任何操作都不会发生。 当key 存在,但保存的不是一个list的时候,会返回error。 **LREM key count value**: 从存于 key 的列表里移除前 count 次出现的值为 value 的元素。 这个 count 参数通过下面几种方式影响这个操作: - count > 0: 从头往尾移除值为 value 的元素。 - count < 0: 从尾往头移除值为 value 的元素。 - count = 0: 移除所有值为 value 的元素。 比如, LREM list -2 “hello” 会从存于 list 的列表里移除最后两个出现的 “hello”。 需要注意的是,如果list里没有存在key就会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。 **LSET key index value**: 设置 index 位置的list元素的值为 value。 更多关于 index 参数的信息,详见 LINDEX。 当index超出范围时会返回一个error。 ```c # 向list集合头部添加元素1 lpush list 1 # 向list集合尾部添加元素2 rpush list 2 # 移除list第一个元素并返回 lpop list # 移除list最后一个元素并返回 rpop list # 移除list最后一个元素并放入list1的第一位置 rpoplpush list list1 # 查看list0-3位置的元素 lrange list 0 3 # 获取list 0索引位置的元素 lindex list 0 # 查看list长度 llen list # 在list的v3元素后添加v4 linsert list after v3 v4 # 从尾到头开始,移除1个v1 lrem list -1 v1 # 替换0位置的元素为v0 lset list 0 v0 ``` **List数据结构** 其底层有linkedList、zipList和quickList这三种存储方式。 当列表对象中元素的长度较小或者数量较少时,通常采用zipList来存储;当列表中元素的长度较大或者数量比较多的时候,则会转而使用双向链表linkedList来存储。 qucikList是由zipList和双向链表linkedList组成的混合体。它将linkedList按段切分,每一段使用zipList来紧凑存储,多个zipList之间使用双向指针串接起来。示意图如下所示:  为了进一步节约空间,Redis还会对zipList进行压缩存储,使用LZF算法进行压缩,可以选择压缩深度。 ### 三、Set集合 ------------ Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的 **常用命令** `SADD key member [member …]`: 添加一个或多个指定的member元素到集合的 key中.指定的一个或者多个元素member 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.如果key 的类型不是集合则返回错误。 `SMEMBERS key`: 返回key集合所有的元素。 `SISMEMBER key member`:返回成员 member 是否是存储的集合 key的成员.如果member元素是集合key的成员,则返回1,如果member元素不是key的成员,或者集合key不存在,则返回0。 `SCARD key`:返回集合存储的key的基数 (集合元素的数量).集合的基数(元素的数量),如果key不存在,则返回 0。 `SREM key member [member …]`:在key集合中移除指定的元素. 如果指定的元素不是key集合中的元素则忽略 如果key集合不存在则被视为一个空的集合,该命令返回0.如果key的类型不是一个集合,则返回错误,返回值为从集合中移除元素的个数。 `SPOP key [count]`:从存储在key的集合中移除并返回一个或多个随机元素。 `SRANDMEMBER key [count]`:随机从该集合中取出n个值。不会从集合中删除 。 `SMOVE source destination member`:将member从source集合移动到destination集合中. 如果该元素成功移除,返回1,如果该元素不是 source集合成员,无任何操作,则返回0。 `SINTER key [key…]`:返回指定所有的集合的成员的交集.如果key不存在则被认为是一个空的集合,当给定的集合为空的时候,结果也为空.(一个集合为空,结果一直为空)。 `SUNION key [key …]`:返回给定的多个集合的并集中的所有成员. `SDIFF key [key …]`:返回一个集合与给定集合的差集的元素. ```c # set集合添加元素 sadd set v1 v2 v3 # 查看set中的所有元素 smembers set # 查看v4是不是set集合中的元素 sismember set v4 # 查看set中的元素个数 scard set # 移除set中的元素v1 srem set v1 # 随机移除并返回2个值 spop set 2 # 随机查看两个值,不删除 srandmember set 2 # 将set中的元素v2,移动到set1中 smove set set1 v2 # 查看set和set1中都存在的元素 sinter set set1 # 查看set和set1中并集元素 sunion set set1 # 查看set中有,set1中没有的元素 sdiff set set1 ``` **Set数据结构** Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。 一个算法,随着数据的增加,执行时间的长短,如果是O(1),数据增加,查找数据的时间不变。 Set数据结构是用哈希表实现的。在新增数据时会进行去重。  ### 四、Hash哈希 ------------ Redis hash 是一个键值对集合,是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似Java里面的Map<String,Object>。  **常用命令** `HSET key field value`:设置 key 指定的哈希集中指定字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段在哈希集中存在,它将被重写。 `HGET key field`: 返回 key 指定的哈希集中该字段所关联的值,当字段不存在或者 key 不存在时返回nil。 `HMSET key field value [field value …]`:设置 key 指定的哈希集中指定字段的值。该命令将重写所有在哈希集中存在的字段。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。 `HEXISTS key field`:返回hash里面field是否存在,返回1,hash里面包含该field,0 表示hash里面不包含该field或者key不存在。 `HKEYS key`:返回 key 指定的哈希集中所有字段的名字。当 key 指定的哈希集不存在时返回空列表。 `HVALS key`:返回 key 指定的哈希集中所有字段的值。 `HINCRBY key field increment`:增加 key 指定的哈希集中指定字段的数值。如果 key 不存在,会创建一个新的哈希集并与 key 关联。如果字段不存在,则字段的值在该操作执行前被设置为 0,HINCRBY 支持的值的范围限定在 64位 有符号整数。 `HSETNX key field value`:只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段已存在,该操作无效果。 ```c # 添加一个hash对象,并添加name和age hset hashkey name zhangsan age 18 # 查看hash对象的name字段对应的值 hget hashkey name # 添加一个user对象,并添加相关属性 hmset user name lisi age 18 sex 男 # 查看user对象是否有score属性 hexists user score # 查看user所有属性 hkeys user # 查看user所有属性值 hvals user # 给user的age属性值+3 hincrby user age 3 # 给user添加score为90 hsetnx user score 90 ``` **Hash数据结构** 其底层实现方式有两种,一种是zipList,这种是当hash结构的V值较小的时候使用的编码方式,较大时使用使用hashtable。 ### 五、Zset(sorted set) 有序集合 ------------ Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。 不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。 因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。 访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。 **常用命令** `ZADD key [NX|XX] [CH] [INCR] score member [score member …]`: 将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。 如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。如果key存在,但是类型不是有序集合,将会返回一个错误应答。 分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。 参数说明: - XX: 仅仅更新存在的成员,不添加新成员。 - NX: 不更新存在的成员。只添加新成员。 - CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。 - INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。 `ZRANGE key start stop [WITHSCORES]`:返回存储在有序集合key中的指定范围的元素。 返回的元素可以认为是按得分从最低到最高排列。 如果得分相同,将按字典排序。 参数start和stop都是基于零的索引,即0是第一个元素,1是第二个元素,以此类推。 它们也可以是负数,表示从有序集合的末尾的偏移量,其中-1是有序集合的最后一个元素,-2是倒数第二个元素,等等。 start和stop都是全包含的区间,因此例如ZRANGE myzset 0 1将会返回有序集合的第一个和第二个元素。 可以传递WITHSCORES选项,以便将元素的分数与元素一起返回。这样,返回的列表将包含value1,score1,…,valueN,scoreN,而不是value1,…,valueN。 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。 `ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]`: 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 `ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]`:返回有序集合中指定分数区间内的成员,分数由高到低排序。 `ZINCRBY key increment member`:为有序集key的成员member的score值加上增量increment。如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。如果key不存在,就创建一个只含有指定member成员的有序集合。 `ZREM key member [member …]`:删除该集合下,指定值的元素 。 `ZCOUNT key min max`:返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员。 `ZRANK key member`:返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。排名以0为底,也就是说,score值最小的成员排名为0。 ```c # 添加一个zset,设置评分并添加元素 zadd zsetkey 1 one 2 two 3 three # 查看0-3位置的值,并查看积分 zrange zsetkey 0 3 withscores # 查看积分1-3的所有元素 zrangebyscore zsetkey 1 3 # 为one元素积分+2 zincrby zsetkey 2 one # 删除元素one zrem zsetkey one # 统计积分1-3 元素的个数 zcount zsetkey 1 3 # 查看two 元素的排名 zrank zsetkey two ``` **Zset数据结构** zset是Redis提供的一个非常特别的数据结构,常用作排行榜等功能,以用户id为value,关注时间或者分数作为score进行排序。与其他数据结构相似,zset也有两种不同的实现,分别是zipList和skipList。具体使用哪种结构进行存储,规则如下: zipList:满足以下两个条件 - [score,value]键值对数量少于128个; - 每个元素的长度小于64字节;  skipList:不满足以上两个条件时使用跳表、组合了hash和skipList - hash用来存储value到score的映射,这样就可以在O(1)时间内找到value对应的分数; - skipList按照从小到大的顺序存储分数 - skipList每个元素的值都是[socre,value]对  **跳跃表(跳表)** 有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。 **对比有序链表和跳跃表,从链表中查询出51** 1、 有序链表,要查找值为51的元素,需要从第一个元素开始依次查找、比较才能找到共需要6次比较;  2、 跳跃表:从第2层开始,1节点比51节点小,向后比较21节点比51节点小,继续向后比较,后面就是NULL了,所以从21节点向下到第1层在第1层,41节点比51节点小,继续向后,61节点比51节点大,所以从41向下在第0层,51节点为要查找的节点,节点被找到,共查找4次从此可以看出跳跃表比有序链表效率要高; 
李智
2025年3月17日 13:34
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码