【Redis】常见的5种数据类型(上)

文章目录

  • 1 :peach:前言:peach:
  • 2 :peach:Redis 基本的全局命令:peach:
    • 2.1 :apple:keys:apple:
    • 2.2 :apple:exists:apple:
    • 2.3 :apple:del:apple:
    • 2.4 :apple:expire:apple:
    • 2.5 :apple:ttl:apple:
    • 2.6 :apple:type:apple:
  • 3 :peach:单线程架构:peach:
  • 4 :peach:Redis 的 5 种常见数据类型:peach:
  • 5 :peach:String:peach:
    • 5.1 :apple:set:apple:
    • 5.2 :apple:get:apple:
    • 5.3 :apple:mset:apple:
    • 5.4 :apple:mget:apple:
    • 5.5 :apple:incr:apple:
    • 5.6 :apple:incrby:apple:
    • 5.7 :apple:decr:apple:
    • 5.8 :apple:decrby:apple:
    • 5.9 :apple:incrbyfloat:apple:
    • 5.10 :apple:append:apple:
    • 5.11 :apple:getrange:apple:
    • 5.12 :apple:setrange:apple:
    • 5.13 :apple:strlen:apple:
    • 5.14 :apple:内部编码:apple:
    • 5.15 :apple:典型使用场景:apple:
      • 5.15.1 :lemon:缓存功能:lemon:
      • 5.15.2 :lemon:计数功能:lemon:
      • 5.15.3 :lemon:共享会话:lemon:
      • 5.15.4 :lemon:⼿机验证码:lemon:
  • 6 :peach:Hash:peach:
    • 6.1 :apple:hashset:apple:
    • 6.2 :apple:hget:apple:
    • 6.3 :apple:hexists:apple:
    • 6.4 :apple:hdel:apple:
    • 6.5 :apple:hkeys:apple:
    • 6.6 :apple:hvals:apple:
    • 6.7 :apple:hgetall:apple:
    • 6.8 :apple:hmget:apple:
    • 6.9 :apple:hlen:apple:
    • 6.10 :apple:hsetnx:apple:
    • 6.11 :apple:hincrby:apple:
    • 6.12 :apple:内部编码:apple:
    • 6.13 :apple:使用场景:apple:
      • 6.13.1 :lemon:保存用户信息:lemon:
      • 6.13.2 :lemon:作为缓存:lemon:


1 🍑前言🍑

在正式介绍 5 种常见的数据结构之前,了解⼀下 Redis 的⼀些全局命令、数据结构和内部编码、单线程命令处理机制是⼗分必要的,它们能为后⾯内容的学习打下⼀个良好的基础。


2 🍑Redis 基本的全局命令🍑

2.1 🍎keys🍎

返回所有满⾜样式(pattern)的 key,⽀持如下统配样式:

  • h?llo 匹配 hello , hallo 和 hxllo等;
  • h*llo 匹配 hllo 和 heeeello;
  • h[ae]llo 匹配 hello 和 hallo 但不匹配 hillo;
  • h[^e]llo 匹配 hallo , hbllo , … 但不匹配 hello;
  • h[a-b]llo 匹配 hallo 和 hbll。

语法:

 KEYS pattern

命令有效版本:1.0.0 之后
时间复杂度:O(N)
返回值:匹配 pattern 的所有 key。
实例:
在这里插入图片描述
其实这个规则与正则表达式的规则差不多。

2.2 🍎exists🍎

判断某个 key 是否存在。
语法:

EXISTS key [key ...]

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:key 存在的个数。
⽰例:
在这里插入图片描述
由于只有hello和hallo存在,所以返回值为2。

2.3 🍎del🍎

删除指定的 key。
语法:

DEL key [key ...]

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:删除掉的 key 的个数。
⽰例:
在这里插入图片描述

2.4 🍎expire🍎

为指定的 key 添加秒级的过期时间(Time To Live TTL)
语法:

 EXPIRE key seconds

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:1 表⽰设置成功。0 表⽰设置失败。
⽰例:
在这里插入图片描述
等到过了5秒后:
在这里插入图片描述
k1就自动被删除了。

2.5 🍎ttl🍎

获取指定 key 的过期时间,秒级。
语法:

 TTL key

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:剩余过期时间。-1 表⽰没有关联过期时间,-2 表⽰ key 不存在。

⽰例:
在这里插入图片描述

注意: EXPIRE 和 TTL 命令都有对应的⽀持毫秒为单位的版本:PEXPIREPTTL,详细⽤法与EXPIRE 和 TTL类似。

2.6 🍎type🍎

返回 key 对应的数据类型。
语法:

TYPE key

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值: none , string , list , set , zset , hash and stream 等。
⽰例:
在这里插入图片描述
本⼩结只是抛砖引⽟,给出⼏个通⽤的命令,为 5 种数据结构的使⽤做⼀个热⾝,后续章节将对键管理做⼀个更为详细的介绍。


3 🍑单线程架构🍑

我们之前介绍了Redis 使⽤了单线程架构来实现⾼性能的内存数据库服务,但是Redis 单线程模型为什么性能如此之⾼?

在回答这个问题之前我们先要弄明白一件事情:Redis 服务器在同时接受多个客户端时是如何处理数据的?
在这里插入图片描述

其实Redis 内部实现是采取了类似于任务队列这样的方式来进行组织,将客户端的任务先放进任务队列中,然后服务器再从任务队列中取出命令来执行:
在这里插入图片描述
那有人会说如果有两个命令同时到达任务队列应该怎么办呢?其实大家不用想的那么复杂,同时到达随便排序即可,但其实这种场景很少见,大多数命令到达都会有一个时间差。

接下来再来回答为什么单线程还能这么快?
通常来讲,单线程处理能⼒要⽐多线程差,例如有 10000 公⽄货物,每辆⻋的运载能⼒是每次200 公⽄,那么要 50 次才能完成;但是如果有 50 辆⻋,只要安排合理,只需要1 次就可以完成任务。那么为什么 Redis 使⽤单线程模型会达到每秒万级别的处理能⼒呢?可以将其归结为三点:

  • 纯内存访问。Redis 将所有数据放在内存中,内存的响应时⻓⼤约为 100 纳秒,这是 Redis 达到每秒万级别访问的重要基础。
  • 非阻塞 IO。Redis 使⽤ epoll 作为 I/O 多路复⽤技术的实现,再加上 Redis ⾃⾝的事件处理模型将 epoll 中的连接、读写、关闭都转换为事件,不在⽹络 I/O 上浪费过多的时间。不知道多路复用技术的老哥可以移步博主的这两篇文章:
  • 单线程避免了线程切换和竞态产⽣的消耗。单线程可以简化数据结构和算法的实现,让程序模型更简单;其次多线程避免了在线程竞争同⼀份共享数据时带来的切换和等待消耗。

虽然单线程给 Redis 带来很多好处,但还是有⼀个致命的问题:对于单个命令的执⾏时间都是有要求的。如果某个命令执⾏过⻓,会导致其他命令全部处于等待队列中,迟迟等不到响应,造成客⼾端的阻塞,对于 Redis 这种⾼性能的服务来说是⾮常严重的,所以 Redis 是⾯向快速执⾏场景的数据库。所以一般我们写一些命令的时候我们不要写的太长

4 🍑Redis 的 5 种常见数据类型🍑

type 命令实际返回的就是当前键的数据结构类型,它们分别是:String(字符串)、List(列表)、Hash(哈希)、Set(集合)、Zset(有序集合),但这些只是 Redis 对外的数据结构,实际上 Redis 针对每种数据结构都有⾃⼰的底层内部编码实现,⽽且是多种实现,这样 Redis 会在合适的场景选择合适的内部编码。

数据结构内部编码
String(raw) (int) (embstr)
Hash(hashtable) (ziplist)
List(linkedlist) (ziplist) (quicklist)
Set(hashtable) (intset)
Zset(skiplist) (ziplist)

可以看到每种数据结构都有⾄少两种以上的内部编码实现,可以通过object encoding命令查询内部编码:
比如:
在这里插入图片描述
另外在这里我们注意一下这个nil,在C++中其实类似于nullptr,表示空的意思,说明这个数据根本不存在。另外如果我们要清空所有的key值可以使用flushall命令,不过要慎用,否则就等着律师函吧哈哈~~
Redis 一个数据结构使用多个内部编码设计有两个好处:

  • 1)可以改进内部编码,⽽对外的数据结构和命令没有任何影响,这样⼀旦开发出更优秀的内部编码,⽆需改动外部数据结构和命令,例如 Redis 3.2 提供了 quicklist,结合了 ziplist 和 linkedlist 两者的优势,为列表类型提供了⼀种更为优秀的内部编码实现,⽽对⽤⼾来说基本⽆感知。
  • 2)多种内部编码实现可以在不同场景下发挥各⾃的优势,例如 ziplist ⽐较节省内存,但是在列表元素⽐较多的情况下,性能会下降,这时候 Redis 会根据配置选项将列表类型的内部实现转换为linkedlist,整个过程⽤⼾同样⽆感知。

至于各个数据结构在什么情况下使用什么编码我们在后面会给出说明。

5 🍑String🍑

字符串类型是 Redis 最基础的数据类型,关于字符串需要特别注意:

  • 1)⾸先 Redis 中所有的键的类型都是字符串类型,⽽且其他⼏种数据结构也都是在字符串类似基础上构建的,例如列表和集合的元素类型是字符串类型,所以字符串类型能为其他 4 种数据结构的学习奠定基础。
  • 2)其次,字符串类型的值实际可以是字符串,包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;数字,可以是整型或者浮点型;甚⾄是⼆进制流数据,例如图⽚、⾳频、视频等。不过⼀个字符串的最⼤值不能超过 512 MB。

注意:由于 Redis 内部存储字符串完全是按照⼆进制流的形式保存的,所以 Redis 是不处理字符集编码问题的,客户端传⼊的命令中使⽤的是什么字符集编码,就存储什么字符集编码。

5.1 🍎set🍎

将 string 类型的 value 设置到 key 中。如果 key 之前存在,则覆盖,⽆论原来的数据类型是什么。之前关于此 key 的 TTL 也全部失效。
语法:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]

命令有效版本:1.0.0 之后
时间复杂度:O(1)
选项:
SET 命令⽀持多种选项来影响它的⾏为:

  • EX seconds⸺使⽤秒作为单位设置 key 的过期时间。
  • PX milliseconds⸺使⽤毫秒作为单位设置 key 的过期时间。
  • NX ⸺只在 key 不存在时才进⾏设置,即如果 key 之前已经存在,设置不执⾏。
  • XX ⸺只在 key 存在时才进⾏设置,即如果 key 之前不存在,设置不执⾏。

注意:由于带选项的 SET 命令可以被 SETNXSETEXPSETEX 等命令代替,所以之后的版本中,Redis 可能进⾏合并。
返回值:

  • 如果设置成功,返回 OK。
  • 如果由于 SET 指定了 NX 或者 XX 但条件不满⾜,SET 不会执⾏,并返回 (nil)。
    ⽰例:

这里简单的演示一下SETNXSETEX 的用法:
在这里插入图片描述
在这里插入图片描述

5.2 🍎get🍎

获取 key 对应的 value。如果 key 不存在,返回 nil。如果 value 的数据类型不是 string,会报错。
语法:

GET key

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:key 对应的 value,或者 nil 当 key 不存在。
这个很简单就不演示啦。

5.3 🍎mset🍎

⼀次性设置多个 key 的值。
语法:

MSET key value [key value ...]

命令有效版本:1.0.1 之后
时间复杂度:O(N) N 是 key 数量
返回值:永远是 OK
⽰例:
在这里插入图片描述

5.4 🍎mget🍎

⼀次性获取多个 key 的值。如果对应的 key 不存在或者对应的数据类型不是 string,返回 nil。
语法:

MGET key [key ...]

命令有效版本:1.0.0 之后
时间复杂度:O(N) N 是 key 数量
返回值:对应 value 的列表
⽰例:
在这里插入图片描述

那么此时我们肯定会有一个问题?多次set与一次mset效果一样吗?
效果是一样的,但是效率有所不同,一次set就是一次网络请求,而多次set就是多次网络请求,但是一次mset就只有一个网络请求。所以我们要进行多次set的话使用mset命令效率会更高。get也是同理。

所以学会使⽤批量操作,可以有效提⾼业务处理效率,但是要注意,每次批量操作所发送的键的数量也不是⽆节制的,否则可能造成单⼀命令执⾏时间过⻓,导致 Redis 阻塞。

5.5 🍎incr🍎

将 key 对应的 string 表⽰的数字加⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:

INCR key

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:integer 类型的加完后的数值。
⽰例:
在这里插入图片描述

5.6 🍎incrby🍎

将 key 对应的 string 表⽰的数字加上对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:

INCRBY key decrement

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:integer 类型的加完后的数值。
⽰例:
在这里插入图片描述

5.7 🍎decr🍎

将 key 对应的 string 表⽰的数字减⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:

DECR key

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:integer 类型的减完后的数值

用法与incr一致,就不再演示了。

5.8 🍎decrby🍎

将 key 对应的 string 表⽰的数字减去对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:

DECRBY key decrement

命令有效版本:1.0.0 之后
时间复杂度:O(1)
返回值:integer 类型的减完后的数值。
用法与incrby一致,就不再演示了。

5.9 🍎incrbyfloat🍎

将 key 对应的 string 表⽰的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值。如果key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的不是 string,或者不是⼀个浮点数,则报错。允许采⽤科学计数法表⽰浮点数。
语法:

INCRBYFLOAT key increment

命令有效版本:2.6.0 之后
时间复杂度:O(1)
返回值:加/减完后的数值。

注意:减去一个浮点数也是用的是 incrbyfloat,后面跟一个负数即可。

5.10 🍎append🍎

如果 key 已经存在并且是⼀个 string,命令会将 value 追加到原有 string 的后边。如果 key 不存在,则效果等同于 SET 命令。
语法:

APPEND KEY VALUE

命令有效版本:2.0.0 之后
时间复杂度:O(1). 追加的字符串⼀般⻓度较短, 可以视为 O(1).
返回值:追加完成之后 string 的⻓度。
⽰例:
在这里插入图片描述

5.11 🍎getrange🍎

返回 key 对应的 string 的⼦串,由 start 和 end 确定(左闭右闭)。可以使⽤负数表⽰倒数。-1 代表倒数第⼀个字符,-2 代表倒数第⼆个,其他的与此类似。超过范围的偏移量会根据 string 的⻓度调整成正确的值。
语法:

GETRANGE key start end

命令有效版本:2.4.0 之后
时间复杂度:O(N) N 为 [start, end] 区间的⻓度. 由于 string 通常⽐较短, 可以视为是 O(1)
返回值:string 类型的⼦串
⽰例:
在这里插入图片描述

5.12 🍎setrange🍎

覆盖字符串的⼀部分,从指定的偏移开始。
语法:

SETRANGE key offset value

命令有效版本:2.2.0 之后
时间复杂度:O(N), N 为 value 的⻓度. 由于⼀般给的 value ⽐较短, 通常视为 O(1).
返回值:替换后的 string 的⻓度。
⽰例:
在这里插入图片描述

5.13 🍎strlen🍎

获取 key 对应的 string 的⻓度。当 key 存放的类似不是 string 时,报错。
语法:

STRLEN key

命令有效版本:2.2.0 之后
时间复杂度:O(1)
返回值:string 的⻓度。或者当 key 不存在时,返回 0。
⽰例:
在这里插入图片描述

5.14 🍎内部编码🍎

字符串类型的内部编码有 3 种:

  • int:8 个字节的⻓整型。
  • embstr:⼩于等于 39 个字节的字符串。
  • raw:⼤于 39 个字节的字符串。

5.15 🍎典型使用场景🍎

5.15.1 🍋缓存功能🍋

Redis 作为缓冲层,MySQL 作为存储层,绝⼤部分请求的数据都是从 Redis 中获取。由于 Redis 具有⽀撑⾼并发的特性,所以缓存通常能起到加速读写和降低后端压⼒的作⽤。

5.15.2 🍋计数功能🍋

许多应⽤都会使⽤ Redis 作为计数的基础⼯具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源。例如视频⽹站的视频播放次数可以使⽤Redis 来完成:⽤⼾每播放⼀次视频,相应的视频播放数就会⾃增 1。

5.15.3 🍋共享会话🍋

⼀个分布式 Web 服务将⽤⼾的 Session 信息(例如⽤⼾登录信息)保存在各⾃的服务器中,但这样会造成⼀个问题:出于负载均衡的考虑,分布式服务会将⽤⼾的访问请求均衡到不同的服务器上,并且通常⽆法保证⽤⼾每次请求都会被均衡到同⼀台服务器上,这样当⽤⼾刷新⼀次访问是可能会发现需要重新登录,这个问题是⽤⼾⽆法容忍的。

此时我们可以采用Redis管理⽤⼾的 Session 信息,各个服务器可以直接从Redis 中写入以及读取⽤⼾的 Session 信息。

5.15.4 🍋⼿机验证码🍋

很多应⽤出于安全考虑,会在每次进⾏登录时,让⽤⼾输⼊⼿机号并且配合给⼿机发送验证码,然后让⽤⼾再次输⼊收到的验证码并进⾏验证,从⽽确定是否是⽤⼾本⼈。为了短信接⼝不会频繁访问,会限制⽤⼾每分钟获取验证码的频率,例如⼀分钟不能超过 5 次。


6 🍑Hash🍑

⼏乎所有的主流编程语⾔都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组、映射。在 Redis 中,哈希类型是指值本⾝⼜是⼀个键值对结构,形如 key = “key”,value = { {field1, value1 }, …, {fieldN, valueN } }

注意:哈希类型中的映射关系通常称为 field-value,⽤于区分 Redis 整体的键值对(key-value),注意这⾥的 value 是指 field 对应的值,不是键(key)对应的值。

6.1 🍎hashset🍎

设置 hash 中指定的字段(field)的值(value)。
语法:

HSET key field value [field value ...]

命令有效版本:2.0.0 之后
时间复杂度:插⼊⼀组 field 为 O(1), 插⼊ N 组 field 为 O(N)
返回值:添加的字段的个数。

6.2 🍎hget🍎

获取 hash 中指定字段的值。
语法:

HGET key field

命令有效版本:2.0.0 之后
时间复杂度:O(1)
返回值:字段对应的值或者 nil。

6.3 🍎hexists🍎

判断 hash 中是否有指定的字段。
语法:

HEXISTS key field

命令有效版本:2.0.0 之后
时间复杂度:O(1)
返回值:1 表⽰存在,0 表⽰不存在。

6.4 🍎hdel🍎

删除 hash 中指定的字段。
语法:

HDEL key field [field ...]

命令有效版本:2.0.0 之后
时间复杂度:删除⼀个元素为 O(1). 删除 N 个元素为 O(N).
返回值:本次操作删除的字段个数。

6.5 🍎hkeys🍎

获取 hash 中的所有字段。
语法:

 HKEYS key

命令有效版本:2.0.0 之后
时间复杂度:O(N), N 为 field 的个数.
返回值:字段列表。

6.6 🍎hvals🍎

获取 hash 中的所有的值。
语法:

HVALS key

命令有效版本:2.0.0 之后
时间复杂度:O(N), N 为 field 的个数.
返回值:所有的值。

6.7 🍎hgetall🍎

获取 hash 中的所有字段以及对应的值。
语法:

HGETALL key

命令有效版本:2.0.0 之后
时间复杂度:O(N), N 为 field 的个数.
返回值:字段和对应的值。
⽰例:
在这里插入图片描述

6.8 🍎hmget🍎

⼀次获取 hash 中多个字段的值。
语法:

HMGET key field [field ...]

命令有效版本:2.0.0 之后
时间复杂度:只查询⼀个元素为 O(1), 查询多个元素为 O(N), N 为查询元素个数.
返回值:字段对应的值或者 nil。

在使⽤ HGETALL 时,如果哈希元素个数⽐较多,会存在阻塞 Redis 的可能。如果开发⼈员只需要获取部分 field,可以使⽤ HMGET,如果⼀定要获取全部 field,可以尝试使⽤HSCAN命令,该命令采⽤渐进式遍历哈希类型,HSCAN 会在后续章节介绍。

6.9 🍎hlen🍎

获取 hash 中的所有字段的个数。
语法:

HLEN key

命令有效版本:2.0.0 之后
时间复杂度:O(1)
返回值:字段个数。
⽰例:
在这里插入图片描述

6.10 🍎hsetnx🍎

在字段不存在的情况下,设置 hash 中的字段和值。
语法:

HSETNX key field value

命令有效版本:2.0.0 之后
时间复杂度:O(1)
返回值:1 表⽰设置成功,0 表⽰失败。

6.11 🍎hincrby🍎

将 hash 中字段对应的数值添加指定的值。
语法:

HINCRBY key field increment

命令有效版本:2.0.0 之后
时间复杂度:O(1)
返回值:该字段变化之后的值。

⽰例:
在这里插入图片描述
在这里插入图片描述

6.12 🍎内部编码🍎

哈希的内部编码有两种:

  • ziplist(压缩列表):当哈希类型元素个数⼩于 hash-max-ziplist-entries 配置(默认 512 个)、同时所有值都⼩于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使⽤ ziplist 作为哈希的内部实现,ziplist 使⽤更加紧凑的结构实现多个元素的连续存储,所以在节省内存⽅⾯⽐hashtable 更加优秀。
  • hashtable(哈希表):当哈希类型⽆法满⾜ ziplist 的条件时,Redis 会使⽤ hashtable 作为哈希的内部实现,因为此时 ziplist 的读写效率会下降,⽽ hashtable 的读写时间复杂度为 O(1)。

1)当 field 个数⽐较少且没有⼤的 value 时,内部编码为 ziplist。
2)当有 value ⼤于 64 字节时,内部编码会转换为 hashtable。
3)当 field 个数超过 512 时,内部编码也会转换为 hashtable。

6.13 🍎使用场景🍎

6.13.1 🍋保存用户信息🍋

我们先来分析下与关系型数据库(比如MySQL)相比,Redis 的优势与缺陷是什么?

  • 哈希类型是稀疏的,⽽关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的 field,⽽关系型数据库⼀旦添加新的列,所有⾏都要为其设置值,即使为 null。
  • 关系数据库可以做复杂的关系查询,⽽ Redis 去模拟关系型复杂查询,例如联表查询、聚合查询等基本不可能,维护成本⾼。

另外,相⽐于使⽤ JSON 格式的字符串缓存⽤⼾信息,哈希类型变得更加直观,并且在更新操作上变得更灵活。可以将每个⽤⼾的 id 定义为键后缀,多对 field-value 对应⽤⼾的各个属性。

6.13.2 🍋作为缓存🍋

截⾄⽬前为⽌,我们已经能够⽤三种⽅法缓存⽤⼾信息,下⾯给出三种⽅案的实现⽅法和优缺点分析。

  1. 原⽣字符串类型⸺使⽤字符串类型,每个属性⼀个键。
    • 优点:实现简单,针对个别属性变更也很灵活。
    • 缺点:占⽤过多的键,内存占⽤量较⼤,同时⽤⼾信息在 Redis 中⽐较分散,缺少内聚性,所以这种
      ⽅案基本没有实⽤性。
  1. 序列化字符串类型,例如 JSON(PROTOBUF) 格式。
    • 优点:针对总是以整体作为操作的信息⽐较合适,编程也简单。同时,如果序列化⽅案选择合适,内存的使⽤效率很⾼。
    • 缺点:本⾝序列化和反序列需要⼀定开销,同时如果总是操作个别属性则⾮常不灵活。
  1. 哈希类型
    • 优点:简单、直观、灵活。尤其是针对信息的局部变更或者获取操作。
    • 缺点:需要控制哈希在 ziplist 和 hashtable 两种内部编码的转换,可能会造成内存的较⼤消耗。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2807282.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java面试题之Redis

Redis相关面试题解 题一:RDB 和 AOF 机制的优缺点RDB:Redis DataBaseAOF:Append Only File 题二:Redis的过期键的删除策略惰性过期定期过期 题三:Redis线程模型、单线程快的原因题四:简述Redis事务实现1、事…

【Java程序员面试专栏 数据结构】六 高频面试算法题:字符串

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,本篇主要聊聊数组,包括数组合并,滑动窗口解决最长无重复子数组问题,图形法解下一个排列问题,以及一些常见的二维矩阵问题,所以放到一篇Blog中集中练习 题目…

LeetCode LCR 085.括号生成

正整数 n 代表生成括号的对数,请设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 1: 输入:n 3 输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”] 示例 2: 输入&#x…

5.1 Ajax数据爬取之初介绍

目录 1. Ajax 数据介绍 2. Ajax 分析 2.1 Ajax 例子 2.2 Ajax 分析方法 (1)在网页页面右键,检查 (2)找到network,ctrl R刷新 (3)找 Ajax 数据包 (4)…

python-mysql协程并发常用操作封装

目录 前言封装代码测试代码参考 前言 协程异步操作MYSQL是常用的,博主这里在GitHub上找了两个包,databases和aiomysql,第一个包除了mysql外还支持其他的数据库,且操作MYSQL时底层也是使用的aiomysql,但文档内容比较少…

Kodi设置界面语言为中文

Kodi设置界面语言为中文需要注意的一点就是,先要设置:皮肤(Skin)---》字体(Fonts)---》基于Arial字体(Arial based),否则在设置后:区域(Regional&…

OD(10)之Mermaid甘特图(Gantt diagrams)使用详解.md

OD(8)之Mermaid甘特图(Gantt diagrams)使用详解 Author: Once Day Date: 2024年2月24日 漫漫长路才刚刚开始… 全系列文章可参考专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文章: 关于 Mermaid | Mermaid 中文网 (nodejs.cn)Mermaid | Diagramming and charting to…

OpenCV Mat实例详解 六

本文将接着OpenCV Mat实例详解继续介绍OpenCV Mat类的操作符及公有成员函数。 Mat & operator Mat & operator (const Mat &m) 将一个Mat对象赋值个另一个Mat对象。 Mat & operator (const MatExpr &expr) 将一个Mat表达式值赋值给Mat对象 Mat & op…

StarRocks——滴滴OLAP的技术实践与发展方向

原文大佬的这篇StarRocks实践文章整体写的很深入,介绍了StarRocks数仓架构设计、物化视图加速实时看板、全局字典精确去重等内容,这里直接摘抄下来用作学习和知识沉淀。 目录 一、背景介绍 1.1 滴滴OLAP的发展历程 1.2 OLAP引擎存在的痛点 1.2.1 运维…

ArcgisForJS如何将ArcGIS Server发布的点要素渲染为热力图?

文章目录 0.引言1.ArcGIS创建点要素2.ArcGIS Server发布点要素3.ArcgisForJS将ArcGIS创建的点要素渲染为热力图 0.引言 ArcGIS For JS 是一个强大的地理信息系统(GIS)工具,它允许开发者使用 JavaScript 语言来创建各种 GIS 应用。ArcGIS Ser…

深入探究Python多进程编程:Multiprocessing模块基础与实战【第98篇—Multiprocessing模块】

深入探究Python多进程编程:Multiprocessing模块基础与实战 在Python编程中,多进程处理是一项关键的技术,特别是在需要处理大规模数据或执行耗时任务时。为了充分利用多核处理器的优势,Python提供了multiprocessing模块&#xff0…

Linux之JAVA环境配置jdkTomcatMySQL

目录 一. 安装jdk 1.1 查询是否有jdk 1.2 解压 1.3 配置环境变量 二. 安装Tomcat(开机自启动) 2.1 解压 2.2 启动tomcat 2.3 防火墙设置 2.4 创建启动脚本(设置自启动,服务器开启即启动) 三. MySQL安装(…

联想开天昭阳N4620Z笔记本如何恢复出厂麒麟操作系统(图解)

联想开天昭阳N4620Z笔记本简单参数: 中央处理器:KX-6640MA G2 内存:8GB 固态硬盘:512GB SSD 显示器:14.0”FHD 电池:4Cell 操作系统:麒麟KOS中文RTM(试用版) 此款笔…

Unity与Android交互通信系列(5)

在前述文章中,已经使用了AndroidJavaProxy代理接口,本节我们将详细的介绍AndroidJavaProxy代理的用法。正如其名,AndroidJavaProxy是一个代理,它在Android端代码与Unity端代码交互中起一个桥接作用。其一般用法为在Java代码中定义…

网络原理——HTTP

1. 什么是HTTP协议 HTTP是应用层的协议。Java最主要的应用场景是做网站,而网站由 后端(HTTP服务器) 和 前端(浏览器)组成,HTTP协议就是负责这里后端和前端的数据交互。 HTTP3.0 之前在传输层是通过 TCP传…

并发编程(5)共享模型之不可变

7 共享模型之不可变 本章内容 不可变类的使用不可变类设计无状态类设计 7.1 日期转换的问题 问题提出 下面的代码在运行时,由于 SimpleDateFormat 不是线程安全的, 有很大几率出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果,…

PyQt5图片浏览器

PyQt5图片浏览器 实现方式功能实现具体代码 界面实现pillow源码修改ImageQt错误主页面布局 项目开源地址 分享一个图片浏览器 实现方式 qt本身有一个QGraphicsView类用来当做视图框架。 具体参考:如何在pyqt中使用 QGraphicsView 实现图片查看器 不过大佬给的例子…

微信小程序 uniapp+vue餐厅美食就餐推荐系统

本论文根据系统的开发流程以及一般论文的结构分为三个部分,第一个部分为摘要、外文翻译、目录;第二个部分为正文;第三个部分为致谢和参考文献。其中正文部分包括: (1)绪论,对课题背景、意义、目…

eBPF实践篇之基础概念

文章目录 前言基本概念eBPF的生命周期之旅最后 前言 eBPF 是一门革命性的技术,可以在不修改内核源代码或者加载内核模块的情况下,安全和高效地拓展和增强Linux内核的功能,我们主要聚焦在eBPF在网络传输上的应用和实践🚀 基本概念…

AI时代显卡如何选择,B100、H200、L40S、A100、H100、V100 含架构技术和性能对比

AI时代显卡如何选择,B100、H200、L40S、A100、H100、V100 含架构技术和性能对比。 英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择,含架构技术和性能对比带你解决疑惑。 近期,AIGC领域呈现出一片繁荣景象&a…