“Redis缓存:掌握Redis常用五大数据类型“

10 篇文章 0 订阅
8 篇文章 0 订阅

目录

1、Redis中String字符串

1.1 常用命令解释

1.2 原子性

1.3 具有原子性的常用命令

1.4 String数据结构

2、Redis常用数据类型-List列表

2.1 概念

2.2 常用命令

2.3 数据结构

3、Redis常用数据类型-Set集合

3.1 概念

3.2 常用命令

3.3 数据结构

4、Redis常用数据类型-Hash哈希

4.1 概念

4.2 常用命令

4.3 数据结构

5、Redis常用数据类型-Zset有序集合

5.1 概念

5.2 常用命令

5.3 数据结构

5.4 跳表


1、Redis中String字符串

  • 概念
    1. String 是 Redis 最基本的类型,可以理解成与 Memcached 一模一样的类型,一个 key对应一个 value;
    2. String 类型是二进制安全的。意味着 Redis 的 string可以包含任何数据。比如jpg图片或者序列化的对象;
    3. String 类型是 Redis 最基本的数据类型,一个 Redis 中字符串 value 最多可以是 512M;
  • 命令使用

1.1 常用命令解释

1. set : 添加键值对到数据库中。

  • nx: 仅当数据库中不存在该键时,才能设置键值对。
  • xx: 仅当数据库中已存在该键时,才能设置键值对。与 nx 参数互斥。
  • ex: 设置键的过期时间(秒)。
  • px: 设置键的过期时间(毫秒)。与 ex 参数互斥。

示例:

set mykey myvalue nx ex 60

2. get : 获取指定键的值。

示例:

get mykey

3. append : 将给定的值追加到原值的末尾。

示例:

append mykey " additional text"

4. strlen : 获取键值的长度。

示例:

strlen mykey

5. setnx : 仅当键不存在时,设置键的值。

示例:

setnx mykey myvalue

6. incr : 将键中储存的数字值加1。只能对数字值操作,如果键不存在,则设置初始值为1。

示例:

incr mycounter

7. decr : 将键中储存的数字值减1。只能对数字值操作,如果键不存在,则设置初始值为-1。

示例:

decr mycounter

8. incrby key num:对数字定义自增数量

        只能对数字值操作,如果为空,新增值为-1; incrby/decrby <key><步长>将 key 中储存的数字值增减。自定义步长;

1.2 原子性

redis是单线程操作,并不会被打乱;

所谓原子操作是指不会被线程调度机制打断的操作;

这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch(切换到另一个线程);

(1)在单线程中能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间;

(2)在多线程中,不能被其它进程(线程)打断的操作就叫原子操作;

Redis 单命令的原子性主要得益于 Redis 的单线程;

1.3 具有原子性的常用命令

        以下是 Redis 中多个键值操作及范围操作的命令和解释,这些命令都具备原子性(即操作要么全部成功,要么全部失败),确保数据一致性和安全性。

  • mset <key1> <value1> <key2> <value2> ...: 同时设置一个或多个键值对。
    • 如果某个键设置失败,则所有键值对都不会被设置。
    • 示例:
mset key1 value1 key2 value2
  • mget <key1> <key2> <key3> ...: 同时获取一个或多个键的值。
    • 返回顺序与提供的键顺序一致。
    • 示例:
mget key1 key2 key3
  • msetnx <key1> <value1> <key2> <value2> ...: 同时设置一个或多个键值对,仅当所有给定键都不存在时。
    • 如果某个键已经存在,则所有键值对都不会被设置。
    • 示例:
msetnx key1 value1 key2 value2
  • getrange <key> <start> <end>: 获取指定键值的部分字符串,类似于 Java 中的 substring,前包后包。
    • 示例:
getrange mykey 0 4  # 获取从索引0到4的子字符串
  • setrange <key> <offset> <value>: 从指定位置开始,用新的值覆写原值。
    • 示例:
setrange mykey 6 "redis"  # 从索引6开始,用"redis"覆盖原值
  • setex <key> <seconds> <value>: 设置键值的同时,设置过期时间(单位:秒)。
    • 示例:
setex mykey 60 "value"  # 设置键mykey的值为"value",并在60秒后过期
  • getset <key> <value>: 设置新的值,并返回旧值。
    • 示例:
getset mykey "newvalue"  # 设置mykey的新值为"newvalue",并返回旧值
1.4 String数据结构

        String 的数据结构为简单动态字符串(Simple Dynamic string,缩写 SDS)。是可以修改的字符串,内部结构实现上类似于 Java的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配;

        如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度len。当字符串长度小于 1M时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M的空间。需要注意的是字符串最大长度为 512M。

2、Redis常用数据类型-List列表

2.1 概念

list列表是单键多值;

Redis 列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)

它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差;

2.2 常用命令

1. lpush <key> <value1> <value2> ...: 从左边插入一个或多个值到列表中。

lpush mylist value1 value2 value3

2. rpush <key> <value1> <value2> ...: 从右边插入一个或多个值到列表中。

rpush mylist value1 value2 value3

3. lpop <key>: 从左边移出并返回列表中的第一个值。

lpop mylist

4. rpop <key>: 从右边移出并返回列表中的最后一个值。

rpop mylist

5. rpoplpush <source> <destination>: 从源列表右边移出一个值,并将该值插入到目标列表的左边。

rpoplpush mylist1 mylist2

6. lrange <key> <start> <stop>: 按照索引范围获取列表中的元素(从左到右)。

索引从0开始,-1表示最后一个元素。

lrange mylist 0 -1  # 获取所有元素

7. lindex <key> <index>: 按照索引获取列表中的元素(从左到右)。

lindex mylist 0  # 获取第一个元素

8. llen <key>: 获取列表的长度。

llen mylist

9. linsert <key> before|after <pivot> <value>: 在指定值的前面或后面插入新值。

linsert mylist befor epivotValue newValue
linsert mylist after pivotValue newValue

10. lrem <key> <count> <value>: 从列表中移除指定数量的值(从左到右)。

  • count > 0:从头到尾移除 count 个值。
  • count < 0:从尾到头移除 count 个值。
  • count = 0:移除所有匹配的值。
lrem mylist 2 value  # 移除从左到右第一个和第二个匹配的值

11. lset <key> <index> <value>: 将列表指定索引的值替换成新值。

lset mylist 1 newValue  # 将索引为1的值替换为newValue
2.3 数据结构

List 的数据结构为快速链表 quickList;

  1. 首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表;
  2. 它将所有的元素紧挨着一起存储,分配的是一块连续的内存;
  3. 当数据量比较多的时候才会改成 quicklist;
  4. 因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next;

        Redis 将链表和 zipList结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余;

3、Redis常用数据类型-Set集合

3.1 概念
  1. Redis set对外提供的功能与 List 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set集合内的重要接口,这个也是 List所不能提供的;
  2. Redis 的 Set是 string类型的无序集合。它底层其实是一个value为 nuil的 hash表,所以添加,删除,查找的复杂度都是 O(1);
  3. 一个算法,随着数据的增加,执行时间的长短,如果是 O(1),数据增加,查找数据的时间不变;
3.2 常用命令

1. sadd <key> <value1> <value2> ...: 将一个或多个元素加入到集合中,已经存在的元素将被忽略。

sadd myset value1 value2

2. smembers <key>: 取出该集合的所有值。

smembers myset

3. sismember <key> <value>: 判断集合中是否包含该值,存在返回1,不存在返回0。

sismember myset value1

4. scard <key>: 返回集合的元素个数。

scard myset

5. srem <key> <value1> <value2> ...: 删除集合中的一个或多个元素。

srem myset value1 value2

6. spop <key>: 随机从集合中移出并返回一个值。

spop myset

7. srandmember <key> <n>: 随机从集合中取出 n 个值,不会从集合中删除。

srandmember myset 2

8. smove <source> <destination> <value>: 将集合中的一个值从一个集合移动到另一个集合。

smove myset1 myset2 value1

9. sinter <key1> <key2> ...: 返回一个或多个集合的交集元素。

sinter myset1 myset2

10. sunion <key1> <key2> ...: 返回一个或多个集合的并集元素。

sunion myset1 myset2

11. sdiff <key1> <key2> ...: 返回第一个集合与其他集合的差集元素(即在第一个集合中但不在其他集合中的元素)。

sdiff myset1 myset2
3.3 数据结构
  1. Set数据结构是dict字典,字典是用哈希表实现的;
  2. Java中的HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象;
  3. Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值;

4、Redis常用数据类型-Hash哈希

4.1 概念
  1. Redis hash 是一个键值对集合;
  2. Redis hash 是一个 string类型的 field 和 value 的映射表,hash 特别适合用于存储对象;
  3. 类似 Java 里面的 Map<String, Object>;
  4. 用户 ID 为查找的 key,存储的 value 用户对象包含姓名,年龄,生日等信息,如果用普通的 key/value 结构来存储;

附加:redis的hash数据类型是默认的吗?多少大小的值会被分为ziplist,多少大小的值会被分为hashtable?

  • 在Redis中,hash数据类型的默认行为是当hash的field和value的数量小于64个,并且所有field和value的大小都小于64字节时,hash会使用ziplist进行存储。否则,当hash的field和value的数量超过64个或者任意field或value的大小超过64字节时,hash会使用hashtable进行存储。
  • 需要注意的是,这里提到的64个和64字节都是默认值,可以通过修改配置文件或者使用命令进行调整。
4.2 常用命令

1. hset <key> <field> <value>: 给哈希表中的字段赋值。

    hset: 将指定哈希表中的字段设置为指定值。如果字段已存在,其旧值将被覆盖。

hset myhash field1 value1

2. hget <key> <field>: 从哈希表中取出指定字段的值。

    hget: 返回哈希表中指定字段的值。如果字段不存在,则返回 nil。

hget myhash field1

3. hmset <key> <field1> <value1> <field2> <value2> ...: 批量设置哈希表的字段值。

    hmset: 一次性设置多个字段及其值到哈希表中。如果某个字段已存在,其旧值将被覆盖。

hmset myhash field1 value1 field2 value2

4. hexists <key> <field>: 检查哈希表中指定的字段是否存在。

    hexists: 检查哈希表中指定字段是否存在。如果存在,返回1;否则返回0。

hexists myhash field1

5. hkeys <key>: 列出哈希表中的所有字段。

hkeys myhash

6. hvals <key>: 列出哈希表中的所有值。

hvals myhash

7. hincrby <key> <field> <increment>: 为哈希表中指定字段的值加上增量。

     hincrby: 将哈希表中指定字段的值加上指定增量。如果字段不存在,则将其值初始化为0,然后再加上增量。

hincrby myhash field1 1
hincrby myhash field1 -1

8. hsetnx <key> <field> <value>: 当且仅当字段不存在时,设置哈希表中指定字段的值。

    hsetnx: 只有当指定字段不存在时,才将其值设置为指定值。如果字段已存在,此命令将不起作用。

hsetnx myhash field1 value1
4.3 数据结构

        Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表);当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable;

5、Redis常用数据类型-Zset有序集合

5.1 概念
  • 有序不重复集合。
  • Redis 有序集合 zset 与普通集合 set 非常相似,是一个没有重复元素的字符串集合;
  • 不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复的;
  • 因为元素是有序的,所以也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素;
  • 访问有序集合的中间元素也是非常快的,因此能够使用有序集合作为一个没有重复成员的智能列表;

附加:

1. Zset按照元素的分数score来进行排序

  • Redis的有序集合(sorted set)是按照元素的分数(score)来进行排序的,而不是按照插入的顺序或者数据的大小来进行排序;
  • 每个有序集合的元素都会关联一个分数,这个分数用来进行排序。当多个元素的分数相同时,会根据元素的字典序(lexicographical order)来进行排序;
  • 通过使用不同的命令,可以向有序集合中添加元素,获取指定范围内的元素,按照分数或字典序进行排序等操作;
  • 需要注意的是,有序集合的元素是唯一的,不允许重复的元素存在。如果多个元素的分数相同,那么它们会按照字典序进行排序;

2. Zset的分数在不指定的情况下都为0,如果是多值插入,那么也是0(然后Zset会默认根据自己的字典来进行数据的排序)

  • 默认插入的时候每个value的分数都为0;
5.2 常用命令

1. zadd <key> <score1> <value1> <score2> <value2> ...: 将一个或多个成员元素及其分数值加入到有序集合中。

zadd myzset 1 member1 2 member2

2. zrange <key> <start> <stop> [withscores]: 返回有序集合中,指定索引范围内的元素。

    可以使用 WITHSCORES 选项返回元素的分数。

zrange myzset 0 1 withscores

3. zrangebyscore <key> <min> <max> [withscores] [limit <offset> <count>]: 返回有序集合中,分数值介于 min 和 max 之间的所有成员。

    可以使用 WITHSCORES 选项返回成员的分数。

    可以使用 LIMIT 选项控制返回结果的数量。

zrangebyscore myzset 0 100 withscores limit 0 10

4. zrevrangebyscore <key> <max> <min> [withscores] [limit <offset> <count>]: 返回有序集合中,分数值介于 max 和 min 之间的所有成员,按分数值递减(从大到小)的次序排列。

    可以使用 WITHSCORES 选项返回成员的分数。

    可以使用 LIMIT 选项控制返回结果的数量。

zrevrangebyscore myzset 100 0 withscores limit 0 10

5. zincrby <key> <increment> <value>: 为有序集合中指定成员的分数加上增量。

zincrby myzset 2 member1

6. zrem <key> <value>: 删除有序集合中指定的成员。

zrem myzset member1

7. zcount <key> <min> <max>: 统计有序集合中,分数值介于 min 和 max 之间的成员数量。

zcount myzset 0 100

8. zrank <key> <value>: 返回有序集合中指定成员的排名(从0开始),按分数值递增(从小到大)的顺序。

zrank myzset member1
5.3 数据结构

        SortedSet(zset)是 Redis 提供的一个非常特别的数据结构,一方面它等价于 Java的数据结构 Map<String,Double〉,可以给每一个元素 value 赋予一个权重 score,另一方面它又类似于 TreeSet,内部的元素会按照权重 score 进行排序,可以得到每个元素的名次,还可以通过 score 的范围来获取元素的列表;

zset 底层使用了两个数据结构;

(1) hash:hash的作用就是关联元素 value 和权重 score,保障元素 value 的唯一性,可以通过元素 value 找到相应的 score 值;

(2) 跳跃表:跳跃表的目的在于给元素 value 排序,根据 score 的范围获取元素列表;

5.4 跳表

简介:

        有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单;

跳表(Skip List)是一种用于有序元素的数据结构,它在插入、删除、查找元素时具有较高的效率,平均时间复杂度为 O(log n)。跳表是一种类似于平衡树的数据结构,但其实现方式更加简单。

跳表的核心思想是通过添加多级索引来加速查找。在跳表中,每个节点都包含一个值以及若干个指向其他节点的指针。这些指针构成了多层级的索引,使得我们可以通过跳过部分节点来快速定位目标节点。顶层的指针组成了一个快速路径,能够迅速定位到较远的节点,而底层的指针则构成了详细路径,用于具体的查找。

简单的说:

        跳表是一种数据结构,用于有序元素的存储和快速检索。它的设计类似于链表,但是在链表的基础上增加了多级索引。这些索引使得跳表可以在查找元素时跳过一些不必要的节点,从而提高了查找效率。

举个例子,想象一下有一个存储数字的跳表。这个跳表的每个节点都包含一个数字,并且节点之间有一些指针连接它们。这些指针不是简单地连接相邻节点,而是连接到其他级别的节点,形成了一个多层结构。

当你要查找一个特定的数字时,跳表会从顶层开始检查,并沿着索引向下移动,直到找到目标数字或确定它不存在。由于跳表是有序的,所以可以根据节点的值比较来决定下一步应该向左还是向右移动。

跳表的优点之一是它的查找操作效率很高,因为它可以跳过一些不必要的节点。而且跳表的插入和删除操作也相对简单,不像其他数据结构那样需要频繁地重新平衡。

总的来说,跳表是一种高效的数据结构,特别适用于那些需要快速查找和动态更新的场景。

跳表的结构如下图所示:

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值