当前位置: 首页 > news >正文

Redis 数据类型 String 字符串

Redis 中的 String 数据类型 是最基础且使用最广泛的数据类型之一。它本质上是一个字节序列,可以存储各种类型的数据,如字符串、整数、浮点数等,其字符串类型的值包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;还可以存储⼆进制流数据,例如图⽚、⾳频、视频等,不过⼀个字符串的最⼤值不能超过 512 MB。String 数据类型支持多种操作,包括设置、获取、更新、追加等。

String 数据类型的特点

  • 存储任意数据:Redis 的 String 数据类型可以存储任意类型的数据,包括文本、数字等。

  • 原子操作:所有对 String 的操作都是原子性的,即在执行过程中不会被其他操作打断。

  • 内存优化:Redis 会根据 String 的大小和内容自动选择合适的内部编码方式,以优化内存使用。

String 的内部编码

Redis 的 String 数据类型有三种内部编码方式:

  1. int:当字符串值可以表示为整数时,使用 8 字节的长整型编码。

  2. embstr:当字符串长度较短(小于等于 39 字节)时,使用嵌入式字符串编码。

  3. raw:当字符串长度较长时,使用原始字符串编码。

由于 Redis 内部存储字符串完全是按照⼆进制流的形式保存的,所以 Redis 是不处理字符集编码问题的,客⼾端传⼊的命令中使⽤的是什么字符集编码,就存储什么字符集编码。有时候我们存储的值为中文汉字时,读取时会变成乱码,这时我们可以使用如下命令重新启动客户端:
redis-cli --raw

使用 --raw 参数可以让 redis-cli原始二进制形式输出数据,而不是进行格式化,这对于处理二进制数据或非 ASCII 字符(如中文)非常有用。

常见命令

设置和获取键值

SET

将 string 类型的 value 设置到 key 中。如果 key 之前存在则覆盖,⽆论原来的数据类型是什么,之前关于此 key 的 TTL 也全部失效。
语法:
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
时间复杂度:O(1)
选项:
  • SET 命令⽀持多种选项来影响它的⾏为:
  • EX seconds⸺使⽤秒作为单位设置 key 的过期时间。
  • PX milliseconds⸺使⽤毫秒作为单位设置 key 的过期时间。
  • NX ⸺只在 key 不存在时才进⾏设置,即如果 key 之前已经存在,设置不执⾏。
  • XX ⸺只在 key 存在时才进⾏设置,即如果 key 之前不存在,设置不执⾏。
注意:带选项的 SET 命令可以被 SETNX SETEX PSETEX 等命令代替。
返回值:
  • 如果设置成功,返回 OK。
  • 如果由于 SET 指定了 NX 或者 XX 但条件不满⾜,SET 不会执⾏,并返回 (nil)。

示例:

MSET

⼀次性设置多个 key 的值。
语法:
MSET key value [key value ...]
时间复杂度:O(N) N 是 key 数量
返回值:永远是 OK
⽰例:

GET

获取 key 对应的 value。如果 key 不存在,返回 nil。如果 value 的数据类型不是 string,会报错。
语法:
GET key
时间复杂度:O(1)
返回值:key 对应的 value,或者 nil 当 key 不存在。

MGET

⼀次性获取多个 key 的值。如果对应的 key 不存在或者对应的数据类型不是 string,返回 nil。
语法:
MGET key [key ...]
时间复杂度:O(N) N 是 key 数量
返回值:对应 value 的列表
⽰例:

使⽤ mget / mset 由于只进行一次 IO 就可以完成多条命令,可以有效地减少了⽹络时间,所以性能相较更⾼。假设⽹络耗时 1 毫秒,命令执⾏时间耗时 0.1 毫秒,则执⾏时间如表所⽰。

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

APPEND

如果 key 已经存在并且是⼀个 string,命令会将 value 追加到原有 string 的后边。如果 key 不存在,则效果等同于 SET 命令。
语法:
APPEND KEY VALUE
时间复杂度:O(1)
返回值:追加完成之后 string 的⻓度。
⽰例:

GETRANGE

返回 key 对应的 string 的⼦串,由 start 和 end 确定(左闭右闭),可以使⽤负数表⽰倒数。-1 代表倒数第⼀个字符,-2 代表倒数第⼆个,其他的与此类似。超过范围的偏移量会根据 string 的⻓度调整成正确的值。
语法:
GETRANGE key start end
时间复杂度:O(N). N 为 [start, end] 区间的⻓度. 由于 string 通常⽐较短, 可以视为是 O(1)
返回值:string 类型的⼦串
⽰例:

SETRANGE

覆盖字符串的⼀部分,从指定的偏移开始。
语法:
SETRANGE key offset value
时间复杂度:O(N), N 为 value 的⻓度. 由于⼀般给的 value ⽐较短, 通常视为 O(1).
返回值:替换后的 string 的⻓度。
⽰例:

STRLEN

获取 key 对应的 string 的⻓度。当 key 存放的类似不是 string 时,报错。
语法:
STRLEN key
时间复杂度:O(1)
返回值:string 的⻓度。或者当 key 不存在时,返回 0。
⽰例:

计数命令

INCR

将 key 对应的 string 表⽰的数字加⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:
INCR key
时间复杂度:O(1)
返回值:integer 类型的加完后的数值。
⽰例:

INCRBY

将 key 对应的 string 表⽰的数字加上对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:
INCRBY key decrement
时间复杂度:O(1)
返回值:integer 类型的加完后的数值。
⽰例:

DECR

将 key 对应的 string 表⽰的数字减⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:
DECR key
时间复杂度:O(1)
返回值:integer 类型的减完后的数值。
⽰例:

DECYBY

将 key 对应的 string 表⽰的数字减去对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。
语法:
DECRBY key decrement
时间复杂度:O(1)
返回值:integer 类型的减完后的数值。
⽰例:

INCRBYFLOAT

将 key 对应的 string 表⽰的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的不是 string,或者不是⼀个浮点数,则报错。允许采⽤科学计数法表⽰浮点数。
语法:
INCRBYFLOAT key increment
时间复杂度:O(1)
返回值:加/减完后的数值。
⽰例:

典型使⽤场景

缓存(Cache)功能

Redis 作为缓冲层,存储热点数据(如频繁访问的数据), MySQL 作为存储层,作为持久化存储层,存储所有数据, 绝⼤部分请求的数据都是从 Redis 中获取,因为Redis 是基于内存的键值存储,读取速度极快,能够快速响应用户的请求 。由于 Redis 具有⽀撑⾼并发的特性,所以缓存通常能起到加速读写和降低后端压⼒的作⽤。

以下是 Redis 和 MySQL 之间的数据交互流程:

  1. 读取数据

    • 应用程序首先尝试从 Redis 中读取数据。

    • 如果 Redis 中存在数据(缓存命中),直接返回数据。

    • 如果 Redis 中不存在数据(缓存未命中),应用程序从 MySQL 中读取数据,然后将数据写入 Redis 缓存,最后返回数据给用户。

  2. 写入数据

    • 应用程序将数据写入 MySQL。

    • 写入 MySQL 后,更新 Redis 缓存,以保证数据的一致性。

    • 如果数据更新频繁,可以使用失效策略,如设置缓存的过期时间,让 Redis 在一定时间后自动失效缓存。

下⾯的伪代码模拟业务数据访问过程:
  • 假设业务是根据⽤⼾ uid 获取⽤⼾信息,⾸先从 Redis 获取⽤⼾信息,我们假设⽤⼾信息保存在 "user:info:<uid>" 对应的键中:
UserInfo getUserInfo(long uid) {
// 根据 uid 得到 Redis 的键
string key = "user:info:" + uid;
// 尝试从 Redis 中获取对应的值
string value = Redis 执⾏命令:get key;
// 如果缓存命中(hit)
if (value != null) {
 // 假设我们的⽤⼾信息按照 JSON 格式存储
 UserInfo userInfo = JSON 反序列化(value);
 return userInfo;
}
  • 如果没有从 Redis 中得到⽤⼾信息,及缓存 miss,则进⼀步从 MySQL 中获取对应的信息,随后写⼊缓存并返回:
// 如果缓存未命中(miss)
if (value == null) {
 // 从数据库中,根据 uid 获取⽤⼾信息
 UserInfo userInfo = MySQL 执⾏ SQL:select * from user_info where uid = <uid>
 // 如果表中没有 uid 对应的⽤⼾信息
 if (userInfo == null) {
 响应 404
 return null;
 }
 // 将⽤⼾信息序列化成 JSON 格式
 String value = JSON 序列化(userInfo);
 // 写⼊缓存,为了防⽌数据腐烂(rot),设置过期时间为 1 ⼩时(3600 秒)
 Redis 执⾏命令:set key value ex 3600 
 // 返回⽤⼾信息
 return userInfo;
}
通过增加缓存功能,在理想情况下,每个⽤⼾信息,⼀个⼩时期间只会有⼀次 MySQL 查询,极⼤地提升了查询效率,也降低了 MySQL 的访问数。
与 MySQL 等关系型数据库不同的是,Redis 没有表、字段这种命名空间,⽽且也没有对键名有强制要求(除了不能使⽤⼀些特殊字符)。但设计合理的键名,有利于防⽌键冲突和项⽬的可维护性,⽐较推荐的⽅式是使⽤ "业务名:对象名:唯⼀标识:属性" 作为键名。例如 MySQL 的数据库名为 vs,⽤⼾表名为 user_info,那么对应的键可以使⽤"vs:user_info:6379:name" 来表⽰。

计数(Counter)功能

许多应⽤都会使⽤ Redis 作为计数的基础⼯具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源。例如视频⽹站的视频播放次数可以使⽤ Redis 来完成:⽤⼾每播放⼀次视频,相应的视频播放数就会⾃增 1。
// 在 Redis 中统计某视频的播放次数
long incrVideoCounter(long vid) {
key = "video:" + vid;
long count = Redis 执⾏命令:incr key
return counter;
}

共享会话(Session)

⼀个分布式 Web 服务将⽤⼾的 Session 信息(例如⽤⼾登录信息)保存在各⾃的服务器中,但这样会造成⼀个问题:出于负载均衡的考虑,分布式服务会将⽤⼾的访问请求均衡到不同的服务器上,并且通常⽆法保证⽤⼾每次请求都会被均衡到同⼀台服务器上,这样当⽤⼾刷新⼀次访问是可能会发现需要重新登录,这个问题是⽤⼾⽆法容忍的。
为了解决这个问题,可以使⽤ Redis 将⽤⼾的 Session 信息进⾏集中管理,如图 2-13 所⽰,在这种模式下,只要保证 Redis 是⾼可⽤和可扩展性的,⽆论⽤⼾被均衡到哪台 Web 服务器上,都集中从 Redis 中查询、更新 Session 信息。
很多应⽤出于安全考虑,会在每次进⾏登录时,让⽤⼾输⼊⼿机号并且配合给⼿机发送验证码,
然后让⽤⼾再次输⼊收到的验证码并进⾏验证,从⽽确定是否是⽤⼾本⼈。为了短信接⼝不会频繁访问,会限制⽤⼾每分钟获取验证码的频率,例如⼀分钟不能超过 5 次,如图所⽰。
string SendCaptcha(phoneNumber) {
 key = "shortMsg:limit:" + phoneNumber;
 // 设置过期时间为 1 分钟 (60 秒),使⽤ NX,只在不存在 key 时才能设置成功
 bool r = Redis 执⾏命令:set key 1 ex 60 nx
 if (r == false) {
 // 说明之前设置过该⼿机的验证码了
 long c = Redis 执⾏命令:incr key
 if (c > 5) {
 // 说明超过了⼀分钟 5 次的限制了
 return nullptr;
 }
 }
 
 // 说明要么之前没有设置过⼿机的验证码;要么次数没有超过 5 次
 string validationCode = ⽣成随机的 6 位数的验证码();
 
 validationKey = "validation:" + phoneNumber;
 // 验证码 5 分钟(300 秒)内有效
 Redis 执⾏命令:set validationKey validationCode ex 300;
 
 // 返回验证码,随后通过⼿机短信发送给⽤⼾
 return validationCode ;
}
// 验证⽤⼾输⼊的验证码是否正确
bool CheckCaptcha(phoneNumber, validationCode) {
 validationKey = "validation:" + phoneNumber;
 
 string value = Redis 执⾏命令:get validationKey;
 if (value == null) {
 // 说明没有这个⼿机的验证码记录,验证失败
 return false;
 }
 
 if (value == validationCode) {
 return true;
 } else {
 return false;
 }
}

相关文章:

  • java商城解决方案
  • NixHomepage - 简单的个人网站
  • C#运动控制——轴IO映射
  • Fiori APP配置中的Semantic object 小bug
  • SSE与Websocket详解,SSE实现对话框流式输出
  • react项目引入tailwindcss不生效解决方案
  • 手撕Transformer编码器:从Self-Attention到Positional Encoding的PyTorch逐行实现
  • NPDP学习笔记 -产品经理(第二版)-第三章 产品创新流程
  • 开源模型应用落地-安全合规篇-用户输入价值观判断(四)
  • 电脑显示器无信号是什么原因?查看解决方法
  • js实现点击音频实现播放功能
  • Node.js入门篇
  • C/C++后端开发面经
  • Docker 存储管理:卷、绑定挂载、临时存储
  • Ubuntu 22.04完整安装Xinference及解决依赖报错
  • Docker 在 Java 开发中的实践与应用:解锁高效容器化部署新姿势
  • xss总结
  • cameralib 安装
  • Web安全攻防入门教程——hvv行动详解
  • anolis os 8.9安装jenkins
  • 空间做网站/驻马店网站seo
  • 网站建设排名优化技巧/google搜索引擎入口下载
  • 网站域名有了_网站如何建设/深圳外贸网站制作
  • 微商城网站建设多少钱/百度百科怎么创建自己
  • 被k掉的网站怎么做才能有收录/如何制作公司网页
  • 免费建设个人手机网站/北京官网seo收费