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

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;
 }
}


http://www.kler.cn/a/541507.html

相关文章:

  • 2025 年 2 月 TIOBE 指数
  • Lombok使用指南
  • 从零开始:使用Jenkins实现高效自动化部署
  • Visual Studio Code (VSCode) 的基本设置指南,帮助你优化开发环境
  • 使用PyCharm创建项目以及如何注释代码
  • AI分支知识之机器学习,深度学习,强化学习的关系
  • 【linux学习指南】模拟线程封装与智能指针shared_ptr
  • 高级java每日一道面试题-2025年02月01日-框架篇[SpringBoot篇]-Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
  • Scala语言的区块链
  • Log4j定制JSON格式日志输出
  • Scala语言的系统运维
  • docker swarm里搭建Selenium Grid分布式测试集群,测试节点随时在线,无需反复启停,效率增倍
  • 构建Ubuntu unminimized的docker镜像
  • 支付宝安全发全套解决方案
  • spring-ai
  • Java 大视界 -- Java 大数据在智能体育中的应用与赛事分析(80)
  • Android 稳定性优化总结
  • 【LeetCode: 378. 有序矩阵中第 K 小的元素 + 二分】
  • 缓存组件<keep-alive>
  • 关于SpringBoot的理解
  • 无人机常见的定位方式
  • Lisp语言的测试开发
  • 十三. Redis 应用问题和解决方案思想
  • 从零到一:我的元宵灯谜小程序诞生记
  • 从MySQL优化到脑力健康:技术人与效率的双重提升
  • IDEA接入DeepSeek