• Redis - String|Hash|List|Set|Zset基本数据类型的介绍



    基本数据结构包含:字符串(strings)、 散列(hashes)、 列表(lists)、 集合(sets)、 有序集合(sorted sets)五种。这五种数据结构在我们工作中经常使用到,面试过程中经常被问到,因此熟练掌握这5种基本数据结构的使用和应用场景是Redis知识最基础也是最重要的部分。

    1. 字符串(strings)

    类型介绍:

    字符串是Redis最简单的储存类型,它存储的值可以是字符串整数或者浮点数,对整个字符串或者字符串的其中一部分执行操作;对整数或者浮点数执行自增(increment)或者自减(decrement)操作。

    Redis的字符串是一个由字节组成的序列,跟java里面的ArrayList有点类似,采用预分配冗余空间的方式来减少内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M

    应用场景:

    字符串类型在工作中使用广泛,主要用于缓存数据,提高查询性能。比如存储登录用户信息、电商中存储商品信息、可以做计数器(想知道什么时候封锁一个IP地址(访问超过几次))等等。

    操作命令:

    set key value: 添加一条String类型数据
    get key: 获取一条String类型数据
    mset key1 value1 key2 value2: 添加多条String类型数据
    mget key1 key2: 获取多条String类型数据
    incr key: 自增(+1)
    incrby key step: 按照步长(step)自增
    decr key: 自减(-1)
    decrby key step: 按照步长(step)递减

    实操:

    # 插入字符串  
    >set username zhangsan  
    "OK"   
    # 获取字符串  
    >get username  
    "zhangsan"    
    # 插入多个字符串  
    >mset age 18 address bj  
    "OK"   
    # 获取多个字符串  
    >mget username age  
     1)  "zhangsan"  
     2)  "18"    
    # 自增  
    >incr num  
    "1"  
    >incr num  
    "2"   
    # 自减  
    >decr num  
    "1"    
    # 指定步长自增  
    >incrby num 2  
    "3"  
    >incrby num 2  
    "5"   
    # 指定步长自减  
    >decrby num 3  
    "2"   
    # 删除  
    >del num  
    "1"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2. 散列(hashes)

    类型介绍:

    散列相当于Java中的HashMap,内部是无序字典。实现原理跟HashMap一致。一个哈希表有多个节点,每个节点保存一个键值对。

    与Java中的HashMap不同的是,rehash 的方式不一样,因为 Java 的 HashMap 在字典很大时,rehash 是个耗时的操作,需要一次性全部 rehash。Redis 为了高性能,不能堵塞服务,所以采用了渐进式 rehash 策略。

    渐进式 rehash 会在 rehash 的同时,保留新旧两个 hash 结构,查询时会同时查询两个 hash 结构,然后在后续的定时任务中以及 hash 操作指令中,循序渐进地将旧 hash 的内容一点点迁移到新的 hash 结构中。当搬迁完成了,就会使用新的hash结构取而代之。

    当 hash 移除了最后一个元素之后,该数据结构自动被删除,内存被回收。

    应用场景:

    Hash也可以同于对象存储,比如存储用户信息,与字符串不一样的是,字符串是需要将对象进行序列化(比如json序列化)之后才能保存,而Hash则可以讲用户对象的每个字段单独存储,这样就能节省序列化和反序列的时间。

    此外还可以保存用户的购买记录,比如key为用户id,field为商品id,value为商品数量。同样还可以用于购物车数据的存储,比如key为用户id,field为商品id,value为购买数量等等。

    操作命令:

    # 设置属性
    hset keyname field1 value1 field2 value2
    # 获取某个属性值
    hget keyname field
    # 获取所有属性值
    hgetall keyname
    # 删除某个属性
    hdel keyname field
    # 获取属性个数
    hlen keyname
    # 按照步长自增/自减某个属性(该属性必须是数字)
    hincrby keyname field step
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实操:

    # 插入 hash 数据
    >hset userInfo username zhangsan age 18 address bj
    "3"
    # 获取 hash 单条 field 数据
    >hget userInfo username
    "zhangsan"
    >hget userInfo age
    "18"
    # 获取 hash 多个 field 数据
    >hmget userInfo username age
    1) "zhangsan"
    2) "18"
    # 获取 hash 所有 field 数据
    >hgetall userInfo
    1) "username"
    2) "zhangsan"
    3) "age"
    4) "18"
    5) "address"
    6) "bj"
    # 获取 hash 的 field 个数
    >hlen userInfo
    "3"
    # 自增 hash 的某个 field
    >hincrby userInfo age 2
    "20"
    >hincrby userInfo age 2
    "22"
    # 自减 hahs 的某个 field(通过自增负步长达到)
    >hincrby userInfo age -2
    "20"
    # 删除 hash 的某个 field
    >hdel userInfo age
    "1"
    # 删除 hash 所有数据
    >del userInfo
    "1"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    3. 列表(lists)

    类型介绍:

    Redis中的lists相当于Java中的LinkedList,实现原理是一个双向链表(其底层是一个快速列表),即可以支持反向查找和遍历,更方便操作。插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n)。

    应用场景:

    lists的应用场景非常多,可以利用它轻松实现热销榜;可以实现工作队列(利用lists的push操作,将任务存在lists中,然后工作线程再用pop操作将任务取出进行执行 );可以实现最新列表,比如最新评论等。

    操作指令

    # 左进
    lpush key value1 value2 value3...
    # 左出
    lpop key
    # 右进
    rpush key value1 value2 value3...
    # 右出
    rpop key
    # 从左往右读取 start和end是下标
    lrange key start end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    实操:

    # 从 list 左边依次插入
    >lpush student zhangsan lisi wangwu
    "3"
    # 从 list 右边插入
    >rpush student tianqi
    "4"
    # 从 list 左边弹出一个
    >lpop liangshan
    "wangwu"
    # 从 list 右边弹出一个
    >rpop liangshan
    "tianqi"
    # 获取 list 下标 0 ~ 1 的数据(左闭右闭)
    >lrange liangshan 0 1
     1) "lisi"
     2) "zhangsan"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4. 集合(sets)

    类型介绍:

    集合类似Java中的HashSet,内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

    应用场景:

    edis的sets类型是使用哈希表构造的,因此复杂度是O(1),它支持集合内的增删改查,并且支持多个集合间的交集、并集、差集操作。可以利用这些集合操作,解决程序开发过程当中很多数据集合间的问题。比如计算网站独立ip,用户画像中的用户标签,共同好友等功能。

    操作指令:

    # 添加内容
    sadd key value1 value2 
    
    # 查询key里所有的值
    smembers key 
    
    # 移除key里面的某个value
    srem key value 
    
    # 随机移除某个value
    spop key 
    
    # 返回两个set的并集
     sunion key1 key2 
    
    # 返回key1踢出交集的那部分(差集)
    sdiff key1 key2 
    
    # 跟siffer相反,返回交集
    sinter key1 key2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    实操:

    # 插入多条数据并去重
    >sadd nums 1 2 3
    "3"
    
    # 插入多条数据并去重
    >sadd nums 1 2 3
    "0"
    
    # 获取所有数据
    >smembers nums
    1) "1"
    2) "2"
    3) "3"
    
    # 删除一条数据,返回的 1 表示删除了一条
    >srem nums 2
    "1"
    
    # 弹出一条数据,返回的 1 表示弹出的数据值为 1
    >spop nums
    "1"
    
    # 插入多条数据并去重
    >sadd nums1 1 2 3
    "3"
    >sadd nums2 2 3 4
    "3"
    
    # 交集
    >sinter nums1 nums2
    1) "2"
    2) "3"
    
    # 差集
    >sdiff nums1 nums2
    1) "1"
    
    # 并集
    >sunion nums1 nums2
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    5. 有序集合(sorted sets)

    类型介绍:

    sorted sets是Redis类似于 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。sorted sets中最后一个 value 被移除后,数据结构自动删除,内存被回收。

    应用场景:

    主要应用于根据某个权重进行排序的队列的场景,比如游戏积分排行榜,设置优先级的任务列表,学生成绩表等。

    操作指令:

    # 添加元素
    zadd key score value [score value...]
    
    # 获取集合的值并按照score从小到大排列, 最小的是最上面
    zrange key start end 
    
    # 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列, 最小的是最上面
    zrangeByScore key score_min score_max 
    
    # 删除
    zrem key value 
    
    # 获取key的集合有多少元素
    zcard key
    
    # 统计分数从小到大有多少元素 (闭区间)
    zcount key score_min score_max 
    
    # 获取value所在位置(从小到大排序,最小的是0)
    zrank key value 
    
    # 获取value所在的位置(从大到小排列, 最大的是0)
    zrevrank key value 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    实操:

    # 插入多条数据和分数并去重及排序
    >zadd rank 66 zhangsan 88 lisi 77 wangwu 99 zhaoliu
    "4"
    
    # 插入多条数据及分数并去重及排序
    >zadd rank 66 zhangsan 88 lisi 77 wangwu 99 zhaoliu
    "0"
    
    # 获取下标 0 ~ 3 的数据(左闭右闭)
    >zrange rank 0 3
     1)  "zhangsan"
     2)  "wangwu"
     3)  "lisi"
     4)  "zhaoliu"
    
    # 获取分数在 77 ~ 99 之间的数据(左闭右闭)
    >zrangeByScore rank 77 99
     1)  "wangwu"
     2)  "lisi"
     3)  "zhaoliu"
    
    # 删除一条数据
    >zrem rank zhaoliu
    "1"
    
    # 查询元素的个数
    >zcard rank
    "3"
    
    # 统计分数在 77 ~ 88 之间的数据(左闭右闭)
    >zcount rank 77 88
    "2"
    
    # 获取指定元素的下标
    >zrank rank zhangsan
    "0"
    
    # 获取指定元素的下标并反转
    >zrevrank rank zhangsan
    "2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口
    【Rust】快速教程——模块mod与跨文件
    浅谈电力物联网时代物联网技术在电力系统中的应用
    Linux安装Redis(详细教程)
    加固技术护城河,比亚迪商用车加速领跑全球电动化进程
    1-10嵌入式Linux系统开发与应用|嵌入式Linux|第三章 Linux编程环境
    【Proteus仿真】【51单片机】拔河游戏设计
    游戏架构设计——高性能并行编程
    基于springboot实现休闲娱乐代理售票平台系统项目【项目源码+论文说明】计算机毕业设计
    华为云两台机器内网互联
  • 原文地址:https://blog.csdn.net/qq_42764468/article/details/126258862