前言

如果问你redis有哪些数据结构,你肯定可以一口气说出五种基本数据结构: String(字符串)Hash(哈希)List(列表)Set(集合)zset(有序集合)

你或许还知道它还有三种特殊的数据结构类型:Geospatial、Hyperloglog、Bitmap。

但如果问你在实际项目中用了哪些数据结构。你是不是觉得好像大大部分只是用了String的数据结构,就算缓存一个对象,也只是通过JSONObject.toJSONString(object)将它转为String存储。取的时候在把这个json字符串转为对象。

那么既然redis提供了5种基本数据结构,肯定都有特定的应用场合。

接下来会针对5种基本数据类型,来演示在实际开发中的应用场景

一、String(字符串)

1. 简介

String 类型是 Redis 中最基本、最常用的数据类型,甚至被很多玩家当成 Redis 唯一的数据类型去使用。String 类型在 Redis 中是二进制安全(binary safe)的,这意味着 String 值关心二进制的字符串,不关心具体格式,你可以用它存储 json 格式或 JPEG 图片格式的字符串。

2、内部编码

如果存储数字的话,是用int(8字节长整型)类型的编码;如果存储非数字,小于等于39字节的字符串,是embstr编码;大于39个字节,则是raw编码。

有关redis的数据内部编码抽空整理一篇文章单独写

3、使用场景

(1) 存储一些配置数据

在前后分离式开发中,有些数据虽然存储在数据库,但是更改特别少。比如有个全国地区表。当前端发起请求后,后台如果每次都从关系型数据库读取,会影响网站整体性能。

我们可以在第一次访问的时候,将所有地区信息存储到redis字符串中,再次请求,直接从数据库中读取地区的json字符串,返回给前端。

(2) 缓存对象

将对象转为json存储,比如商品信息,用户信息。

(3) 数据统计

redis整型可以用来记录网站访问量,某个文件的下载量,签到人数、视频访问量等等。(自增自减

(4) 时间内限制请求次数

比如已登录用户请求短信验证码,验证码在5分钟内有效的场景。
当用户首次请求了短信接口,将用户id存储到redis 已经发送短信的字符串中,并且设置过期时间为5分钟。当该用户再次请求短信接口,发现已经存在该用户发送短信记录,则不再发送短信。

(5) 订单号(全局唯一)

有时候你需要去生成一个全局唯一值的时候可以通过redis生成。关键命令:incrby(原子自增)。

SET order_no 2001 --假设订单号从2001开始,这里vlaue必须是int类型
INCRBY order_no 1 --自增1,这个时候返回2002

(6) 分布式session

当我们用nginx做负载均衡的时候,如果我们每个从服务器上都各自存储自己的session,那么当切换了服务器后,session信息会由于不共享而会丢失,我们不得不考虑第三应用来存储session。

通过我们用关系型数据库或者Redis等非关系型数据库。关系型数据库存储和读取性能远远无法跟Redis等非关系型数据库比。

4、常用命令

--增
set mykey "test" --为键设置新值,并覆盖原有值
setex mykey 10 "hello" -- 设置指定 Key 的过期时间为10秒,在存活时间可以获取value
mset key3 "stephen" key4 "liu" --批量设置键
--删
del mykey --删除已有键
--改
incr mykey --值增加1,若该key不存在,创建key,初始值设为0,增加后结果为1
decrby mykey 5 --值减少5
--查
exists mykey --判断该键是否存在,存在返回 1,否则返回0
get mykey --获取Key对应的value
mget key3 key4 --批量获取键

二、Hash(哈希)

1、简介

Hash的数据结构我们可以简单理解为java中的 Map<String,Map<String,String>,这种结构就特别适合存储对象,上面的String的类型确实也可以存储对象,但每次修改对象中的某一个属性,都要拿出整个json字符串在修改这个属性,之后在重新插入,而hash的接口特点让我们可以只修改该对象的某一个属性。

hash数据类型在存储上述类型的数据时具有比 String 类型更灵活、更快的优势,具体的说,使用 String 类型存储,必然需要转换和解析 json 格式的字符串,即便不需要转换,在内存开销方面,还是 hash 占优势。

2、内部编码

哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable编码。

4、使用场景

(1) Redisson分布式锁

Redisson在实现分布式锁的时候,内部的用的数据就是hash而不是String。因为Redisson为了实现可重入加锁机制。所以在hash中存入了当前线程ID。

(2) 购物车列表

用户id为key商品id为field商品数量为value,恰好构成了购物车的3个要素,如下图所示。

这里涉及的命令如下

hset cart:{用户id} {商品id} 1  # 添加商品

hincrby cart:{用户id} {商品id} 1 # 增加数量

hlen cart:{用户id} # 获取商品总数

hdel cart:{用户id} {商品id} # 删除商品

hgetall cart:{用户id} #获取购物车所有商品

说明:当前仅仅是将商品ID存储到了Redis中,在回显商品具体信息的时候,还需要拿着商品id查询一次数据库。

(3) 缓存对象

hash类型的 (key, field, value) 的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。

在介绍String类型的应用场景时有所介绍,String + json也是存储对象的一种方式,那么存储对象时,到底用String + json还是用hash呢?

两种存储方式的对比如下表所示。

  string + json hash
效率 很高
容量
灵活性
序列化 简单 复杂

一般对象用string + json存储,对象中某些频繁变化的属性可以考虑抽出来用hash存储

3、常用命令

--增
hset key field1 "s" --若字段field1不存在,创建该键及与其关联的Hash, Hash中,key为field1 ,并设value为s ,若字段field1存在,则覆盖
hmset key field1 "hello" field2 "world" -- 一次性设置多个字段
--删
hdel key field1 --删除 key 键中字段名为 field1 的字段
del key -- 删除键
--改
hincrby key field 1 --给field的值加1
--查
hget key field1 --获取键值为 key,字段为 field1 的值
hlen key --获取key键的字段数量
hmget key field1 field2 field3 --一次性获取多个字段
hgetall key --返回 key 键的所有field值及value值
hkeys key --获取key 键中所有字段的field值
hvals key --获取 key 键中所有字段的value值

三、List(列表)

1、简介

List类型是按照插入顺序排序的字符串链表,一个列表最多可以存储2^32-1个元素。我们可以简单理解为就相当于java中的LinkesdList

和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。

2、内部编码

如果列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),使用ziplist编码,否则使用linkedlist编码。

在Redis 3.2之后就都改用ziplist+链表的混合结构,称之为 quicklist(快速链表)。

2、使用场景

有人会考虑用list数据结构来做一些朋友圈的点赞列表、评论列表、排行榜。也不是不可以但我个人觉得这些功能用set或zset来做会更加合适,下面会具体举例。

(1) 消息队列

lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能。

但如果是这样你发现redis作为消息队列是不安全的,它不能重复消费,一旦消费就会被删除,同时做消费者确认ACK也麻烦所以一般在实际开发中一般很少用redis中消息队列,因为现在已经有Kafka、NSQ、RabbitMQ等成熟的消息队列了,它们的功能更加完善。

4、常用命令

--增
lpush mykey a b --若key不存在,创建该键及与其关联的List,依次插入a ,b, 若List类型的key存在,则插入value中
rpush mykey a b --在链表尾部先插入b,在插入a(lpush list a b那么读的时候是b,a的顺序,而rpush是怎么放怎么读出来
--删
del mykey --删除已有键
--改
lset mykey 1 e --从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息
--查
lrange mykey 0 -1 --取链表中的全部元素,其中0表示第一个元素,-1表示最后一个元素。
lrange mykey 0 2 --从头开始,取索引为0,1,2的元素
lpop mykey --获取头部元素,并且弹出头部元素,出栈

四、set(集合)

1、简介

Redis 中的 set和Java中的HashSet 有些类似,它内部的键值对是无序的、唯一的。它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值 NULL。当集合中最后一个元素被移除之后,数据结构被自动删除,内存被回收。

2、编码

如果集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码。

应用场景

既然set的集合的特性是:无序的、唯一的。那么我们考虑在一些唯一的场景下使用它。

(1) 抽奖活动

存储某活动中中奖的用户ID ,因为有去重功能,可以保证同一个用户不会中奖两次。

sadd user 1 2 3 4 5  --把所有员工(名称或编号)放入抽奖箱   

srandmember user 1   -- 抽取一个一等奖(员工可以重复参与抽奖)

spop user 1   -- 抽取一个一等奖(员工不可以重复参与抽奖)

srandmember user 3 --抽取3个二等奖

smembers user --查看当前抽奖箱中参所有员工

scard user  --查看当前抽奖箱中参与抽奖的人数

(2) 点赞

保证一个用户只能点一个赞。key 可以是某某文章、微信朋友圈的文章id

sadd key userId  --点赞(/收藏) 

srem key userId  --取消点赞(/收藏)

smembers key     -- 获取所有点赞(/收藏)用户  

card key  -- 获取点赞用户数量

sismember key userId --判断是否点赞(/收藏)

(3) 好友人脉

key 可以是 用户id

sadd userId1 1 2 3 4 5
sadd userId2 4 5 6 7 8 --某个user的好友id放入集合 sinter userId1 userId2 --获取共同好友 sdiff userId1 userId2 --给user2推荐user1的好友 sismember userId1 5
sismember userId2 5 --验证某个用户是否同时被user1和user2关注

4、常用命令

--增
sadd myset a b c --若key不存在,创建该键及与其关联的set,依次插入a ,b,c。若key存在,则插入value中,若a 在myset中已经存在,则插入了 b 和 c 两个新成员。 --删
spop myset --尾部的b被移出,事实上b并不是之前插入的第一个或最后一个成员
srem myset a d f --若f不存在, 移出 a、d ,并返回2 --改
smove myset myset2 a --将a从 myset 移到 myset2, --查
sismember myset a --判断 a 是否已经存在,返回值为 1 表示存在。
smembers myset --查看set中的内容
scard myset --获取Set 集合中元素的数量
srandmember myset --随机的返回某一成员

五、zset(有序集合)

1、简介

Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。成员是唯一的,但是分数(score)却是可以重复的

2、数据编码

当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码

3、应用场景

既然是 有序的,不可重复的列表,那么就可以做一些排行榜相关的场景。

  1. 排行榜(商品销量,视频评分,用户游戏分数)
  1. 新闻热搜。

4、常用命令

--增
zadd key 2 "two" 3 "three" --添加两个分数分别是 2 和 3 的两个成员
--删
zrem key one two --删除多个成员变量,返回删除的数量
--改
zincrby key 2 one --将成员 one 的分数增加 2,并返回该成员更新后的分数(分数改变后相应它的index也会改变)
--查
zrange key 0 -1 WITHSCORES --返回所有成员和分数,不加WITHSCORES,只返回成员
zrange key start stop --按照元素的分值从小到大的顺序返回从start 到stop之间的所有元素
zscore key three --获取成员 three 的分数
zrangebyscore key 1 2 --获取分数满足表达式 1 < score <= 2 的成员
zcard key --获取 myzset 键中成员的数量
zcount key 1 2 --获取分数满足表达式 1 <= score <= 2 的成员的数量
zrank key member --获取元素的排名,从小到大
zrevrank key member --获取元素的排名,从大到小

这篇文章就先写到这里,有关redis的数据内部编码,抽空在单独写一篇文章。

Redis五种数据结构及真实应用场景的更多相关文章

  1. redis 五种数据结构详解(string,list,set,zset,hash)

    redis 五种数据结构详解(string,list,set,zset,hash) Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存 ...

  2. 2.Redis五种数据结构

    2.Redis五种数据结构2.1 预备2.1.1 全局命令2.1.2 数据结构和内部编码2.1.3 单线程架构2.2 字符串2.2.1 命令2.2.2 内部编码2.2.3 典型使用场景2.3 哈希2. ...

  3. 【Redis】redis 五种数据结构详解(string,list,set,zset,hash)

    redis 五种数据结构详解(string,list,set,zset,hash) Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存 ...

  4. Redis(一)、Redis五种数据结构

    Redis五种数据结构如下: 对redis来说,所有的key(键)都是字符串. 1.String 字符串类型 是redis中最基本的数据类型,一个key对应一个value. String类型是二进制安 ...

  5. redis 五种数据结构详解(string,list,set,zset,hash),各种问题综合

    redis 五种数据结构详解(string,list,set,zset,hash) https://www.cnblogs.com/sdgf/p/6244937.html redis 与 spring ...

  6. Redis五种数据结构(Windows Server)

    1.Redis的五种数据结构 这里推荐大家在命名redis的key的时候最好的加上前缀,并且使用 :来分割前缀 ,这里在使用可视化工具查看的时候就比较好区分,比如我的的前缀是 Demo:test:(一 ...

  7. 一口气说出Redis 5种数据结构及对应使用场景,面试要加分的

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...

  8. Redis 五种数据结构详解(string,hash,list,set,zset)

    一.五种数据结构: 1. String--字符串 String 数据结构是简单的 key-value 类型,value 不仅可以是 String,也可以是数字(当数字类型用 Long 可以表示的时候e ...

  9. Redis 5种数据结构及对应使用场景

    本文案例收录在 https://github.com/chengxy-nds/Springboot-Notebook 也当过面试官,面试过不少应聘者,因为是我自己招人自己用,所以我不会看应聘者造火箭的 ...

  10. Redis五种数据结构简介

    Redis五种结构 1.String 可以是字符串,整数或者浮点数,对整个字符串或者字符串中的一部分执行操作,对整个整数或者浮点执行自增(increment)或者自减(decrement)操作. 字符 ...

随机推荐

  1. 七、Spring Boot集成Spring Security之前后分离认证最佳实现

    二.自定义用户名密码认证过滤器RestfulUsernamePasswordAuthenticationFilter 1.注册过滤器方式 使用httpSecurity.addFilter/addFil ...

  2. 2024 xp_CAPTCHA(瞎跑-白嫖版) 4.3最新版安装使用教程

    前言 xp_CAPTCHA(瞎跑-白嫖版)是一个免费的burpsuite插件,具有自动化图形验证码识别的功能.在安装的过程中,我发现网上的教程基本都为其较早的版本,已经不具备参考价值.因而我写下本篇博 ...

  3. Docker for the Virtualization Admin

    Docker is one of the most successful open source projects in recent history, and organizations of al ...

  4. php 如何实现 git diff

    无意间想到这个问题,如何用php来实现git diff,如果实现了这个功能,岂不是能够使用php对在线编辑文件的功能做更进一步的优化和提升? 查了一下还真有这样的库,话不多说,开始执行 compose ...

  5. CSP-J2024 T1(poker/扑克)题解

    洛谷CSP-J 2024自测指路 前情提要:虽然洛谷讨论区里大多数都是倾向用哈希解决该题,但实际上可以用一些邪门小技巧来A这道题awa 先来读题. 题目中说小 P 想知道他至少得向小 S 借多少张牌, ...

  6. Ubuntu apt-cache命令查找可用软件包

    本文GoFace给大家讲解下在Ubuntu及相同包管理的linux系统下如何查找可用软件包.在Ubuntu上大家一般使用apt-get安装软件,如果想查找某一包软件仓库中是否有,并不是使用apt-ge ...

  7. 使用 LLVM 框架创建一个工作编译器,第 1 部分

    使用 LLVM 及其中间表示构建一个自定义编译器 LLVM 编译器基础架构提供了一种强大的方法来优化您使用任何编程语言编写的应用程序.了解本系列文章(由两部分组成)第一部分中有关 LLVM 的基础知识 ...

  8. Linux只gz文件格式压缩与解压缩

    压缩成gz gzip * gzip file 具体参数可使用help查看 解压缩gz gunzip * gunzip file.gz 具体也是可以用help查看

  9. docker之可视化工具

    Docker UI进行Docker管理(单机) 1.拉取镜像 Docker UI进行Docker管理 2.创建docker容器 docker run -it -d --name docker-web ...

  10. Element-UI 中关于 Table 的几个功能点简介(行列的合并和样式、合计行配置等)

    〇.前言 本文记录了关于 Element 框架中 Table 的几个功能点,后续将持续更新. el-table 官网地址:https://element.eleme.cn/#/zh-CN/compon ...