【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 两种内部编码的转换,可能会造成内存的较⼤消耗。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt_纯虚函数的信号和槽

简介 在C中,纯虚函数是一个在基类中声明但没有实现的虚函数。纯虚函数的声明以 “ 0” 结尾。纯虚函数的目的是为了提供一个接口,但是不提供实现。派生类必须实现纯虚函数,否则它也会成为一个抽象类。纯虚函数可以在基类中定义,也…

MySQL--索引结构

索引-索引结构 1. 概述2. 二叉树3. B-Tree4. BTree5. Hash 1. 概述 MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种: 上述是MySQL中所支持的所有的索引结构,下面展示不同的存储引擎对于索引…

力扣382.链表随机节点

Problem: 382. 链表随机节点 文章目录 题目描述思路复杂度Code 题目描述 思路 由水塘抽样易得,当遇到i个元素,有 1 / i 1/i 1/i的概率选择该元素;则在实际操作中我们定义一个下标i从1开始遍历每次判断rand() % i 0(该操作就是判断…

Chrome插件(二)—Hello World!

本小节将指导你从头到尾创建一个基本的Chrome插件,你可以认为是chrome插件开发的“hello world”! 以下详细描述了各个步骤: 第一步:设置开发环境 确保你拥有以下工具: 文本编辑器:如Visual Studio Cod…

2278. 企鹅游行(最大流,拆点)

活动 - AcWing 在南极附近的某个地方,一些企鹅正站在一些浮冰上。 作为群居动物,企鹅们喜欢聚在一起,因此,它们想在同一块浮冰上会合。 企鹅们不想淋湿自己,所以它们只能利用自己有限的跳跃能力,在一块块…

容器_Docker ( 06 )

容器_Docker ( 05 ) Kubernetes 资源对象管理 资源对象文件 模板与帮助信息 资源对象文件优势 命令无法实现高级复杂的功能某些资源对象使用命令无法创建方便管理 , 保存 , 追溯历史 资源对象文件太长 , 记不住怎么办 使用命令创建模板查询帮助信息查询官方手册 生成资源…

区块链游戏解说:什么是 Ultimate Champions

作者:lesleyfootprint.network 编译:cicifootprint.network 数据源:Ultimate Champions Dashboard 什么是 Ultimate Champions Ultimate Champions 是一款免费的奇幻足球和篮球游戏,拥有官方授权的数字卡牌作为区块链上的 NFT…

go interface{} 和string的转换问题

1.遇到的问题 问题来源于,我sql模版拼接遇到的问题。 首先,这样是没有问题的。 var qhx interface{} "qhx"s : qhx.(string)fmt.Println(s) 但是当我在这段代码里用:1.类型断言 var sqlStr "select * from tx_user where username %s" join…

SpringBoot -【SmartInitializingSingleton】基础使用及应用场景

SmartInitializingSingleton 在继续深入探讨 SmartInitializingSingleton接口之前,让我们先了解一下 Spring Framework 的基本概念和背景。Spring Framework 是一个开源的 JavaEE(Java Enterprise Edition)全栈(full-stack&#x…

C++面试题精选与解析

C面试题精选与解析 一、基础与语法 请问C中的指针和引用有什么区别? 指针是一个变量,存储的是另一个变量的内存地址。指针可以被重新赋值以指向另一个不同的对象。而引用是某个变量的别名,一旦引用被初始化为一个变量,就不能改变…

高级统计方法 第4次作业

作业评阅: 概念 2.问题 KNN分类和KNN回归都是KNN算法在不同类型数据上的应用,但它们之间存在明显的区别。 解决的问题类型不同:KNN分类适用于解决分类问题,而KNN回归则适用于解决回归问题。当响应变量是连续的,根据…

windows安装 RabbitMQ

首先打开 RabbitMQ 官网,点击 Get Started(开始) 点击 Download Installation(下载安装)。 这里提供了两种方式进行安装,我们使用第二种方法。 使用 chocolatey以管理用户身份使用官方安装程序 往下滑,第二种方法需要 Erlang 的依赖&#x…

UE蓝图 函数调用(CallFunction)节点和源码

系列文章目录 UE蓝图 Get节点和源码 UE蓝图 Set节点和源码 UE蓝图 Cast节点和源码 UE蓝图 分支(Branch)节点和源码 UE蓝图 入口(FunctionEntry)节点和源码 UE蓝图 返回结果(FunctionResult)节点和源码 UE蓝图 函数调用(CallFunction)节点和源码 文章目录 系列文章目录一、Call…

【Vuforia+Unity】AR06-空间环境识别功能(AreaTargets)

Vuforia原理:把被识别的物体转成图、立体图、柱形图,3D模型、环境模型,然后模型生成Vuforia数据库-导入Unity-参考模型位置开始摆放数字内容,然后参考模型自动隐藏-发布APP-识别生活中实物-数字内容叠加上去! 不论你是否曾有过相关经验,只要跟随本文的步骤,你就可以成功…

uni-app vue3 setup nvue中webview层级覆盖问题

核心就是这两行,🤣发现设置后不能点击了,这个玩意可能只能弹窗打开的时候动态的修改 position: static, zindex: 0onLoad(options > {loadWebview()})function loadWebview() {let pageInfo uni.getSystemInfoSync();width.value pageI…

强大到怀疑人生!AI视频生成必备的工具推荐!

刚发现的超牛逼AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频——播放量随便破百万。地址:跳转提示 - 3MW短网址https://3mw.cn/3ed5 这个Ai漫画推文软件的优势: 1、无需本地部署,对电脑…

Visual Studio:Entity设置表之间的关联关系

1、选择表并右键-》新增-》关联 2、设置关联的表及关联关系并“确定”即可

机器学习模型的过拟合与欠拟合

机器学习模型的训练过程中,可能会出现3种情况:模型欠拟合、模型正常拟合与模型过拟合。其中模型欠拟合与模型过拟合都是不好的情况。下面将会从不同的角度介绍如何判断模型属于哪种拟合情况。 (1)欠拟合与过拟合表现方式 欠拟合…

phtread_cancel函数用于取消线程,但不是实时的

如上图所示,线程函数中没有取消点(一般是一些系统调用----man 7 pthreads查看,自定义函数是无效的),则使用pthread_cancle函数不生效。 解决方法:可以添加pthread_testcancle(); 通过pthread_join回收的…

广联达Linkworks GetAllData 信息泄露漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…