目录
- 1.其他命令
- 1.APPEND
- 2.GETRANGE
- 3.SETRANGE
- 4.STRLEN
- 2.内部编码
- 3.典型使用场景
- 1.缓存(Cache)功能
- 2.计数(Counter)功能
- 3.共享会话(Session)
1.其他命令
1.APPEND
- 功能:
- 如果
key
已经存在并且是⼀个string
,命令会将value
追加到原有string
的后边 - 如果
key
不存在, 则效果等同于SET
命令。
- 如果
- 语法:
APPEND KEY VALUE
- 时间复杂度: O ( 1 ) O(1) O(1),追加的字符串⼀般⻓度较短,可以视为 O ( 1 ) O(1) O(1)
- 返回值:追加完成之后
string
的⻓度(单位是字节)
2.GETRANGE
- 功能:返回
key
对应的string
的⼦串,由start
和end
确定(左闭右闭)- 可以使⽤负数表⽰倒数:-1代表倒数第⼀个字符,-2代表倒数第⼆个,其他的与此类似
- 超过范围的偏移量会根据
string
的⻓度调整成正确的值 - 注意:如果字符串中保存的是汉字,此时进行字串切分,切出来的很可能不是完成的汉字
- 语法:
GETRANGE key start end
- 返回值:
string
类型的字串 - 时间复杂度: O ( N ) O(N) O(N),N为
[start, end]
区间的⻓度,由于string
通常⽐较短,可以视为是O(1)
3.SETRANGE
- 功能:覆盖字符串的⼀部分,从指定的偏移开始
- 注意:针对不存在的
key
,也可以操作,不过会把offset
之前的内容填充成0x00
- 注意:针对不存在的
- 语法:
SETRANGE key offset value
- 返回值:替换后的
string
的长度 - 时间复杂度: O ( N ) O(N) O(N),N为
value
的⻓度,由于string
通常⽐较短,可以视为是O(1)
4.STRLEN
- 功能:获取
key
对应的string
的长度,当key
存放的类型不是string
时,报错 - 语法:
STRLEN key
- 返回值:
string
的⻓度- 当
key
不存在时,返回0
- 时间复杂度: O ( 1 ) O(1) O(1)
2.内部编码
- 字符串类型的内部编码有3种
int
:8个字节的长整形embstr
:小于等于39个字节的字符串raw
:大于39个字节的字符串
- Redis会根据当前值的类型和长度动态决定使用哪种内部编码实现
# 整形
> set key 2333
OK
> object encoding key
"int"# 短字符串
> set key "hello"
OK
> object encoding key
"embstr"# ⼤于39个字节的字符串
> set key "one string greater than 39 bytes ........"
OK
> object encoding key
"raw
3.典型使用场景
1.缓存(Cache)功能
-
典型缓存使用场景:Redis作为缓冲层,MySQL作为存储层,绝⼤部分请求的数据都是从Redis中获取。由于Redis具有⽀撑⾼并发的特性,所以缓存通常能起到加速读写和降低后端压⼒的作⽤
-
模拟以上业务数据访问过程:
- 根据用户uid获取用户信息
UserInfo GetUserInfo(long uid) { ... }
- 先从Redis获取用户信息,假设用户信息保存在
"user:info:<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){响应404return null;}// 将⽤⼾信息序列化成 JSON 格式String value = JSON 序列化 (userInfo);// 写⼊缓存,为了防⽌数据腐烂(rot),设置过期时间为 1 ⼩时(3600秒)Redis 执⾏命令: set key value ex 3600// 返回用户信息return userInfo; }
- 根据用户uid获取用户信息
-
通过增加缓存功能,在理想情况下,每个⽤⼾信息,⼀个⼩时期间只会有⼀次MySQL查询,极⼤地提升了查询效率,也降低了MySQL的访问数
-
注意:
- 与MySQL等关系型数据库不同的是,Redis没有表、字段这种命名空间,⽽且也没有对键名有强制要求(除了不能使⽤⼀些特殊字符)
- 但**设计合理的键名,有利于防⽌键冲突和项⽬的可维护性**,⽐较推荐的⽅式是使⽤"业务名:对象名:唯⼀标识:属性"作为键名
- 例如:MySQL的数据库名为
vs
,⽤⼾表名为user_info
- 那么对应的键可以使⽤ “
vs:user_info:2333"、"vs:user_info:2333:name
” 来表⽰ - 如果当前Redis只会被⼀个业务使⽤,可以省略业务名"
vs
:"
- 那么对应的键可以使⽤ “
- 例如:MySQL的数据库名为
- 如果键名过长,则可以使⽤团队内部都认同的缩写替代
- 例如:"
user:2333:friends:messages:6666
"可以被"u:2333:fr:m:666
"代替 - 毕竟键名过⻓,还是会导致Redis的性能明显下降的
- 例如:"
2.计数(Counter)功能
-
许多应⽤都会使⽤Redis作为计数的基础⼯具,它可以实现快速计数、查询缓存的功能,同时数 据可以异步处理或者落地到其他数据源
-
示例:在Redis中统计某视频的播放次数
long IncrVideoCounter(long vid) {key = "video:" + vid;long count = Redis 执⾏命令:incr keyreturn counter; }
注意:实际中要开发⼀个成熟、稳定的真实计数系统,要⾯临的挑战远不⽌如此简单:防作弊、按 照不同维度计数、避免单点问题、数据持久化到底层数据源等
3.共享会话(Session)
-
为什么?:⼀个分布式Web服务将⽤⼾的Session信息(例如⽤⼾登录信息)保存在各⾃的服务器中,但这样会造成⼀个问题:出于负载均衡的考虑,分布式服务会将⽤⼾的访问请求均衡到不同的服务器上,并且通常⽆法保证⽤⼾每次请求都会被均衡到同⼀台服务器上,这样当⽤⼾刷新⼀次访问是可能会发现需要重新登录,这个问题是⽤⼾⽆法容忍的
-
问题解决:使⽤Redis将⽤⼾的Session信息进⾏集中管理,在这种模式下,只要保证Redis是⾼可⽤和可扩展性的,⽆论⽤⼾被均衡到哪台Web服务器上,都集中从Redis中查询、更新Session信息
-
示例:手机验证码
String SendCapcha(String phoneNumber) {key = "shortMsg:limit:" + phoneNumber;// 设置过期时间为1分钟// 使用NX,只在不存在key时才能设置成功bool r = Redis 执行命令:set key ex 60 nxif(r == false){// 说明之前设置过该手机的验证码了long c = Redis 执行命令:incr keyif(c > 5){// 说明超过一分钟5次的限制了// 限制发送return null;}}// 说明要么之前没有设置过⼿机的验证码;要么次数没有超过 5 次String validationCode = ⽣成随机的 6 位数的验证码 ();validationKey = "validation:" + phoneNumber;// 验证码 5 分钟内有效Redis 执⾏命令: set validationKey validationCode ex 300;// 返回验证码,随后通过手机短信发送给用户return validationCode; }// 验证用户输入的验证码是否正确 bool VerifyCode(phoneNumber, validationCode) {validationKey = "validation:" + phoneNumber;String value = Redis 执⾏命令: get validationKey;if(value == null) // 说明没有这个手机的验证码记录,验证失败{return false;}if(value == validationCode){return true;}else{return false;} }