文章目录
ps:这是我的个人笔记博客:TinkerBell学习笔记
Redis常用基本数据类型
1. 前言
1.1 Redis键(key操作)
keys *:查看当前库所有 key
set key value:添加一组 k-v
exists key:判断某个 key 是否存在
type key:查看你的 key 是什么类型
del key :删除指定的 key 数据(直接删除,而不是异步删除)
unlink key:根据 value 选择非阻塞删除,仅将 keys 从 keyspace 元数据中删除,真正的删除会在后续异步操作
expire key 10 :为给定的 key 设置过期时间
ttl key:查看还有多少秒过期,-1表示永不过期,-2表示已过期
select:命令切换数据库
dbsize:查看当前数据库的 key 的数量
flushdb:清空当前库
flushall:通杀全部库
2.2 有关原子性
所谓 原子 操作是指不会被线程调度机制打断的操作;
这种操作一旦开始,就一直运行到结束,中间不会有线程切换
-
在单线程中, 能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间。(而redis是单线程的,所以redis中的操作是不会被打断的)
-
在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。
-
Redis 单命令的原子性主要得益于 Redis 的单线程。
2. 字符串(String)
String 类型是最基本的类型,是二进制安全的。意味着 Redis 的 string 可以包含任何数据,比如 jpg 图片或者序列化的对象,只要数据能够存储为字符串类型,redis都能通过k-v的形式存储。
String 类型是 Redis 最基本的数据类型,一个 Redis 中字符串 value 最多可以是 512M。
2.1 常用命令
命令 | 介绍 |
---|---|
set key value | 设置指定 key 的值 |
setnx key value | 只有在 key 不存在时设置 key 的值 |
get key | 获取指定 key 的值 |
mget key1 value1 key2 value2 … | 设置一个或多个指定 key 的值 |
met key1 key2 … | 获取一个或多个指定 key 的值 |
strlen key | 返回 key 所储存的字符串值的长度 |
incr key | 将 key 中储存的数字值增一 |
decr key | 将 key 中储存的数字值减一 |
exists key | 判断指定 key 是否存在 |
del key(通用) | 删除指定的 key |
expire key seconds(通用) | 给指定 key 设置过期时间 |
2.2 数据结构
内部结构实现上类似于 Java 的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,字符串大小小于1M时,扩容都是加倍现有的空间大小,如果空间大小一旦超过1M,每次扩容只会多扩容1M的空间,注意字符串最大长度是512M。
2.3 应用场景
-
缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力
-
计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。
-
session: 常见方案spring session + redis实现session共享
-
分布式锁: 利用 setnx key value 命令可以实现一个最简易的分布式锁(存在一些缺陷,通常不建议这样实现分布式锁)。
3. 列表(List)
单键多值
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JI60P37p-1663775748914)(https://s2.loli.net/2022/09/21/qL5VnBkPaHl6ozu.png “List”)]
3.1 常用命令
命令 | 介绍 |
---|---|
rpush key value1 value2 … | 在指定列表的尾部(右边)添加一个或多个元素 |
lpush key value1 value2 … | 在指定列表的头部(左边)添加一个或多个元素 |
lset key index value | 将指定列表索引 index 位置的值设置为 value |
lpop key | 移除并获取指定列表的第一个元素(最左边) |
rpop key | 移除并获取指定列表的最后一个元素(最右边) |
llen key | 获取列表元素数量 |
lrange key start end | 获取列表 start 和 end 之间 的元素 |
通过 RPUSH/LPOP 或者 LPUSH/RPOP实现队列 :
> RPUSH myList value1
(integer) 1
> RPUSH myList value2 value3
(integer) 3
> LPOP myList
"value1"
> LRANGE myList 0 1
1) "value2"
2) "value3"
> LRANGE myList 0 -1
1) "value2"
2) "value3"
通过 RPUSH/RPOP或者LPUSH/LPOP 实现栈 :
> RPUSH myList2 value1 value2 value3
(integer) 3
> RPOP myList2 # 将 list的头部(最右边)元素取出
"value3"
3.2 数据结构
List 的数据结构为快速链表 quickList。
-
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。
- 它将所有的元素紧挨着一起存储,分配的是一块连续的内存。
-
当数据量比较多的时候才会改成 quicklist。
- 因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next。
-
Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。quicklist结构图如下:
3.3 应用场景
信息流展示
- 举例 :最新文章、最新动态。
- 相关命令 : LPUSH、LRANGE。
4. Hash(哈希)
Redis hash 是一个键值对集合。
Redis hash 是一个 String 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。( 可以理解为Java中的Map<String,Object> )
4.1 常用命令
命令 | 介绍 |
---|---|
hset key field value | 设置指定哈希表中指定字段的值 |
hsetnx key field value | 只有指定字段不存在时设置指定字段的值 |
hmset key field1 value1 field2 value2 … | 同时将一个或多个 field-value (域-值)对设置到指定哈希表中 |
hget key field | 获取指定哈希表中指定字段的值 |
hmget key field1 field2 … | 获取指定哈希表中一个或者多个指定字段的值 |
hgetall key | 获取指定哈希表中所有的键值对 |
hexists key field | 查看指定哈希表中指定的字段是否存在 |
hdel key field1 field2 … | 删除一个或多个哈希表字段 |
hlen key | 获取指定哈希表中字段的数量 |
hincryby key field increment | 对指定哈希中的指定字段做运算操作(正数为加,负数为减) |
4.2 数据结构
-
Hash 类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。
-
当 field-value 长度较短且个数较少时,使用 ziplist,否则使用 hashtable。
4.3 应用场景
对象数据存储场景
- 举例 :用户信息、商品信息、文章信息、购物车信息。
- 相关命令 :HSET (设置单个字段的值)、HMSET(设置多个字段的值)、HGET(获取单个字段的值)、HMGET(获取多个字段的值)。
5. Set(集合)
Set 对外提供的功能与 List 类似列表的功能。(一个key,对应一个set集合)
-
特殊之处在于 Set 是可以 自动排重 的
-
当需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个成员是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
-
Redis 的 Set 是 String 类型的无序集合。它底层其实是一个 value 为 null 的 hash 表,所以添加,删除,查找的复杂度都是 O(1)
-
你可以基于 Set 轻易实现交集、并集、差集的操作,比如你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。这样的话,Set 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
5.1 常用命令
命令 | 介绍 |
---|---|
sadd key member1 member2 … | 向指定集合添加一个或多个元素 |
SMEMBERS skey | 获取指定集合中的所有元素 |
SCARD key | 获取指定集合的元素数量 |
SISMEMBER key member | 判断指定元素是否在指定集合中 |
SINTER key1 key2 … | 获取给定所有集合的交集 |
SINTERSTORE destination key1 key2 … | 将给定所有集合的交集存储在 destination 中 |
SUNION key1 key2 … | 获取给定所有集合的并集 |
SUNIONSTORE destination key1 key2 … | 将给定所有集合的并集存储在 destination 中 |
SDIFF key1 key2 … | 获取给定所有集合的差集 |
SDIFFSTORE destination key1 key2 … | 将给定所有集合的差集存储在 destination 中 |
SPOP key count | 随机移除并获取指定集合中一个或多个元素 |
SRANDMEMBER key count | 随机获取指定集合中指定数量的元素 |
基本操作 :
SADD mySet value1 value2
(integer) 2
> SADD mySet value1 # 不允许有重复元素,因此添加失败
(integer) 0
> SMEMBERS mySet
1) "value1"
2) "value2"
> SCARD mySet
(integer) 2
> SISMEMBER mySet value1
(integer) 1
> SADD mySet2 value2 value3
(integer) 2
- mySet : value1、value2 。
- mySet2 : value2 、value3 。
求交集 :
SINTERSTORE mySet3 mySet mySet2
(integer) 1
> SMEMBERS mySet3
1) "value2"
求并集 :
SUNION mySet mySet2
1) "value3"
2) "value2"
3) "value1"
求差集 :
SDIFF mySet mySet2 # 差集是由所有属于 mySet 但不属于 A 的元素组成的集合
1) "value1"
5.2 应用场景
需要存放的数据不能重复的场景
- 举例:网站 UV 统计(数据量巨大的场景还是 HyperLogLog更适合一些)、文章点赞、动态点赞等场景。
- 相关命令:SCARD(获取集合数量) 。
需要获取多个数据源交集、并集和差集的场景
- 举例 :共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集) 、订阅号推荐(差集+交集) 等场景。
- 相关命令:SINTER(交集)、SINTERSTORE (交集)、SUNION (并集)、SUNIONSTORE(并集)、SDIFF(差集)、SDIFFSTORE (差集)。
需要随机获取数据源中的元素的场景
- 举例 :抽奖系统、随机。
- 相关命令:SPOP(随机获取集合中的元素并移除,适合不允许重复中奖的场景)、SRANDMEMBER(随机获取集合中的元素,适合允许重复中奖的场景)。
5.3 数据结构
Set 数据结构是字典,字典是用哈希表实现的。
6. Zset(有序集合)
Redis 有序集合 zset 与普通集合 set 非常相似,是一个没有重复元素的字符串有序集合。
不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复的。
因为元素是有序的,所以可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。
访问有序集合的中间元素也是非常快的,因此能够使用有序集合作为一个没有重复成员的智能列表。
6.1 常用命令
命令 | 介绍 |
---|---|
ZADD key score1 member1 score2 member2 … | 向指定有序集合添加一个或多个元素 |
ZCARD KEY | 获取指定有序集合的元素数量 |
ZSCORE key member | 获取指定有序集合中指定元素的 score 值 |
ZINTERSTORE destination numkeys key1 key2 … | 将给定所有有序集合的交集存储在 destination 中,对相同元素对应的 score 值进行 SUM 聚合操作,numkeys 为集合数量 |
ZUNIONSTORE destination numkeys key1 key2 … | 求并集,其它和 ZINTERSTORE 类似 |
ZDIFF destination numkeys key1 key2 … | 求差集,其它和 ZINTERSTORE 类似 |
ZRANGE key start end | 获取指定有序集合 start 和 end 之间的元素(score 从低到高) |
ZREVRANGE key start end | 获取指定有序集合 start 和 end 之间的元素(score 从高到底) |
ZREVRANK key member | 获取指定有序集合中指定元素的排名(score 从大到小排序) |
基本操作 :
> ZADD myZset 2.0 value1 1.0 value2
(integer) 2
> ZCARD myZset
2
> ZSCORE myZset value1
2.0
> ZRANGE myZset 0 1
1) "value2"
2) "value1"
> ZREVRANGE myZset 0 1
1) "value1"
2) "value2"
> ZADD myZset2 4.0 value2 3.0 value3
(integer) 2
- myZset : value1(2.0)、value2(1.0) 。
- myZset2 : value2 (4.0)、value3(3.0) 。
获取指定元素的排名 :
> ZREVRANK myZset value1
0
> ZREVRANK myZset value2
1
求交集 :
> ZINTERSTORE myZset3 2 myZset myZset2
1
> ZRANGE myZset3 0 1 WITHSCORES
value2
5
求并集 :
> ZUNIONSTORE myZset4 2 myZset myZset2
3
> ZRANGE myZset4 0 2 WITHSCORES
value1
2
value3
3
value2
5
求差集 :
> ZDIFF 2 myZset myZset2 WITHSCORES
value1
2
6.2 应用场景
需要随机获取数据源中的元素根据某个权重进行排序的场景
- 举例 :各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。
- 相关命令 :ZRANGE (从小到大排序) 、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。
6.3 数据结构
SortedSet(zset)是 Redis 提供的一个非常特别的数据结构,一方面它等价于 Java 的数据结构 Map<String, Double>,可以给每一个元素 value 赋予一个权重 score,另一方面它又类似于 TreeSet,内部的元素会按照权重 score 进行排序,可以得到每个元素的名次,还可以通过 score 的范围来获取元素的列表。
zset 底层使用了两个数据结构
-
hash,hash 的作用就是关联元素 value 和权重 score(通过key值,能够找到关联的value和score),保障元素 value 的唯一性,可以通过元素 value 找到相应的 score 值
-
跳跃表,跳跃表的目的在于给元素 value 排序,根据 score 的范围获取元素列表
ps:这是我的个人笔记博客:TinkerBell学习笔记