Redis 数据类型 String 字符串
Redis 中的 String 数据类型 是最基础且使用最广泛的数据类型之一。它本质上是一个字节序列,可以存储各种类型的数据,如字符串、整数、浮点数等,其字符串类型的值包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串;还可以存储⼆进制流数据,例如图⽚、⾳频、视频等,不过⼀个字符串的最⼤值不能超过 512 MB。String 数据类型支持多种操作,包括设置、获取、更新、追加等。
String 数据类型的特点
-
存储任意数据:Redis 的 String 数据类型可以存储任意类型的数据,包括文本、数字等。
-
原子操作:所有对 String 的操作都是原子性的,即在执行过程中不会被其他操作打断。
-
内存优化:Redis 会根据 String 的大小和内容自动选择合适的内部编码方式,以优化内存使用。
String 的内部编码
Redis 的 String 数据类型有三种内部编码方式:
-
int
:当字符串值可以表示为整数时,使用 8 字节的长整型编码。 -
embstr
:当字符串长度较短(小于等于 39 字节)时,使用嵌入式字符串编码。 -
raw
:当字符串长度较长时,使用原始字符串编码。
redis-cli --raw
使用 --raw
参数可以让 redis-cli
以原始二进制形式输出数据,而不是进行格式化,这对于处理二进制数据或非 ASCII 字符(如中文)非常有用。
常见命令
设置和获取键值
SET
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
- SET 命令⽀持多种选项来影响它的⾏为:
- EX seconds⸺使⽤秒作为单位设置 key 的过期时间。
- PX milliseconds⸺使⽤毫秒作为单位设置 key 的过期时间。
- NX ⸺只在 key 不存在时才进⾏设置,即如果 key 之前已经存在,设置不执⾏。
- XX ⸺只在 key 存在时才进⾏设置,即如果 key 之前不存在,设置不执⾏。
- 如果设置成功,返回 OK。
- 如果由于 SET 指定了 NX 或者 XX 但条件不满⾜,SET 不会执⾏,并返回 (nil)。
示例:
MSET
MSET key value [key value ...]
GET
GET key
MGET
MGET key [key ...]
使⽤ mget / mset 由于只进行一次 IO 就可以完成多条命令,可以有效地减少了⽹络时间,所以性能相较更⾼。假设⽹络耗时 1 毫秒,命令执⾏时间耗时 0.1 毫秒,则执⾏时间如表所⽰。
操作 | 时间 |
1000 次 get | 1000 x 1 + 1000 x 0.1 = 1100 毫秒 |
1 次 mget 1000 个键 | 1 x 1 + 1000 x 0.1 = 101 毫秒 |
APPEND
APPEND KEY VALUE
GETRANGE
GETRANGE key start end
SETRANGE
SETRANGE key offset value
STRLEN
STRLEN key
计数命令
INCR
INCR key
INCRBY
INCRBY key decrement
DECR
DECR key
DECYBY
DECRBY key decrement
INCRBYFLOAT
INCRBYFLOAT key increment
典型使⽤场景
缓存(Cache)功能
以下是 Redis 和 MySQL 之间的数据交互流程:
-
读取数据
-
应用程序首先尝试从 Redis 中读取数据。
-
如果 Redis 中存在数据(缓存命中),直接返回数据。
-
如果 Redis 中不存在数据(缓存未命中),应用程序从 MySQL 中读取数据,然后将数据写入 Redis 缓存,最后返回数据给用户。
-
-
写入数据
-
应用程序将数据写入 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;
}
计数(Counter)功能
// 在 Redis 中统计某视频的播放次数
long incrVideoCounter(long vid) {
key = "video:" + vid;
long count = Redis 执⾏命令:incr key
return counter;
}
共享会话(Session)
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;
}
}