文章目录
redis的string类型
在前面已经了解过了redis下常用的几种数据类型了
本篇文章,将深入地去了解string这个类型的:相关指令用法,常用的业务使用场景等
string的常用命令
这个部分首先来了解string类型的常用命令
set和get
虽然前面已经见过了这两个的用法
但是,这里更多的是用string这个类型,来更加完善对这个命令的认识
完整用法如下:
set key value [EX seconds|PX milliseconds|KEEPTTL] [NX|XX]
get key
对于set来说,我们是可以在后面跟一些选项操作的
EX:设置过期时间(s)
PX:设置过期时间(ms)
KEEPTTL:Redis 6.0+ 新增的核心参数 / 选项,核心作用是:在修改 key 的值时,保留该 key 原有过期时间(TTL),而不是重置 / 清除过期时间 【过往的情况:会把这个key的清空,默认变为持久化】
NX:如果key不存在就设置,存在返回nil
XX:如果key存在就设置,不存在返回nil
注意,这两个部分的选项内:EX、PX、KEEPTTL是互斥的,NX和XX是互斥的【逻辑互相冲突】
flushall
这个命令就是删除当前所有的key:效果等同于drop database
这个命令在生产环境中不能用!
因为这样子会导致缓存瞬间消失,后端的数据库很容易瞬间崩溃!这是线上环境最忌讳的事情
删除成功后:客户端会显示一个OK
mset和mget
这个的核心作用就是:
一次性设置多个key<->value或者是一次性获取多个key对应的value
MSET key value [key value ...]
MGET key [key ...]
但是:
这里要注意:mset是没办法像set那样去设置EX什么的:
127.0.0.1:6379> mset key1 value1 EX 10 key2 value2 PX 5000
OK
127.0.0.1:6379> keys *
1) "key1"
2) "EX"
3) "PX"
4) "key2"
这里能够发现:设置的EX和PX被解析成key了
所以如果需要进行一次性设置多个key的话,这个过期时间等选项就是无法使用的
这个还是有一定用处的:
因为redis是通过网络来进行服务端客户端之间的通信的,如果能够一次插入多个key,那么就可以减少网络通信的次数
时间复杂度:O(K) 【K为插入key的个数】
但是:也不能说一次性真的就插入成千上万个key:
因为redis本身就是单线程的工作模型,一次性插入过多的key会导致这个请求把其他请求阻塞
setex、psetex、setnx
SETNX:SETNX key value,当key不存在时才能插入:

SETEX、PSETEX:SETEX|PSETEX key seconds value
插入key的时候顺便进行设置过期时间:如果key存在:就会覆盖原有的过期时间和value
PSETEX的只是把过期时间换成ms而已
这两个命令更多像是为了使用者的方便而设计的
而且这个在语义上看着就很符合日常使用习惯,所以一般更加建议使用这个命令来进行设置过期时间
incr、incrby、decr、decrby、incrbyfloat
用法如下所示:
incr key // value + 1
incrby key increment // value + n
decr key // value - 1
decrby key decrement // value - n
incrbyfloat key increment // value + n 【n是浮点数(double),可以使用正负】
前面了解到:string的底层编码方式有三种:int、embstr、raw
因为很多时候我们是拿redis来做一些计数统计的,所以很可能存储的value就是一个数字
redis为了能够快速的进行操作,如果是存储整数的话,就会把数字的value用int来存储
为了能够快速对存储的value数字进行一些操作【如增加、减少】,redis就提供了一些命令:
127.0.0.1:6379> set k1 1
OK
127.0.0.1:6379> set k2 2
OK
127.0.0.1:6379> incr k1
(integer) 2
127.0.0.1:6379> incrby k2 20
(integer) 22
127.0.0.1:6379> incrbyfloat k2 2.5
"24.5"
127.0.0.1:6379> type k2
string
127.0.0.1:6379> incr k2
(error) ERR value is not an integer or out of range
127.0.0.1:6379> object encoding k2
"embstr"
decr的相关操作这里就不演示了,用法和incr的类似
这里需要说明几点:
- incr、incrby、decr、decrby操作的必须是整数类型,否则会出错【value is not an integer】
- 整数的大小是有上限的,就是类似于C++的int类型,超出限制会报错 【out of range】
- 上述几个命令的n可以为负数,效果和正数相反(incrbyfloat没有提供减法版本)
- redis中存储浮点数的类型是embstr:所以当变成浮点数后,没办法使用前四个指令
上述的五个指令,时间复杂度均为O(1),这个很好理解
当然,在面对多个客户端的请求的时候,这里的计数操作必然是原子的!
因为redis的工作模型就是单线程的多路复用,本身就是串行的,原子的。所以不用担心多个客户端对同一个value操作,导致多个客户端的数据不一致问题!
append、strlen、getrange、setrange
append:这个就是给string追加内容用的:返回值是追加后的长度:
127.0.0.1:6379> append key1 woshi
(integer) 6
127.0.0.1:6379> get key1
"1woshi"
就算value为int,也是一样能追加,因为int只是底层的编码方式。在上层看来它的类型依旧是string
如果key不存在:就插入一个默认value为空串的key,然后把内容追加上去即可
如果value类型不为string,会报类型错误:
127.0.0.1:6379> type k
list
127.0.0.1:6379> append k 44
(error) WRONGTYPE Operation against a key holding the wrong kind of value
如果追加的是中文呢:
127.0.0.1:6379> append chi 你好
(integer) 6
127.0.0.1:6379> get chi
"\xe4\xbd\xa0\xe5\xa5\xbd"
我们发现:长度为6
而且取出来后是一个个的十六进制码。
这其实是因为:redis的string是直接存储二进制的,而不是存储编码
而在xshell终端下,默认的编码是utf-8,默认一个汉字是三个字节!
strlen:这个看名字就知道,是求某个string的长度的(单位为byte)
当然还是得注意:
utf-8编码方式下,一个汉字是三个字节,所以【你好】的长度是6个字节!
getsrange:这个和C++的substr是一个功能,就是截取一个string的某个部分:
getrange key start end
【start end】表示的是要截取的区间,注意redis下这里是左闭右闭的区间!
偏移量从0开始,但是,redis支持负向索引,-1表示倒数第一个字符!
127.0.0.1:6379> getrange key1 0 -1
"helloworld"
127.0.0.1:6379> getrange key1 1 -2
"elloworl"
127.0.0.1:6379> getrange key1 -1 0
""
127.0.0.1:6379> getrange key1 5 100
"world"
127.0.0.1:6379> getrange key1 1 0
""
有了负数的话,那进行索引就方便一些了
而且经过实验发现:索引超出范围会被处理成当前的最后一个位置,索引左大右小【数字大小】得到的是空串
我们来尝试截取一下带有中文的串:
127.0.0.1:6379> clear
127.0.0.1:6379> set chi 你好
OK
127.0.0.1:6379> get chi
"\xe4\xbd\xa0\xe5\xa5\xbd"
127.0.0.1:6379> getrange chi 1 -2
"\xbd\xa0\xe5\xa5"
我们发现,就是去把utf-8的码点进行截取,但是如果想看到这个对应的编码样式的话:
我们可以在登录redis-cli的时候加上–raw选项:
127.0.0.1:6379> get chi
你好
127.0.0.1:6379> getrange chi 1 -2
½
此时就会出现一些乱码的问题,因为截取后的这个编码在utf-8找不到
所以,当我们使用这种截取命令的时候,一定要注意编码的问题!
setrange:这个就和getrange相对,这个设置子串,也可以说是替换:
setrange key offset value # 给某个key,在偏移量【0开始,支持负向】开始的位置,替换为value
127.0.0.1:6379> set key helloworld
OK
127.0.0.1:6379> setrange key 2 out
10
127.0.0.1:6379> get key
heoutworld
【Tips】:这里的替换是直接从offset的位置开始,直接进行覆盖的替换!
所以,如果value过长:就会导致新的这个串非常长!

如果给一个不存在的key进行替换:
127.0.0.1:6379> setrange k 2 hello
7
127.0.0.1:6379> get k
hello
127.0.0.1:6379>
ubuntu@VM-12-10-ubuntu:~$ redis-cli
127.0.0.1:6379> get k
"\x00\x00hello"
退出–raw模式,我们可以发现,redis会自动填充\x00,直到足够偏移量位置!
所以,这里依旧要注意的是编码问题,否则也会出现乱码的情况
string的编码方式
string的编码方式就是下列这三种:

int表示的是八个字节的整数
embstr的上限为39,超过39会转化为raw【字符数组】
具体的可以通过object encoding key查询编码方式
这里的一些数字不太需要记忆,因为这个具体使用是要看使用场景的:
比如当前村的都是100长度左右的string,明显使用embstr更合适,所以可以考虑配置一下这个数字:
1.redis是否支持直接修改配置文件
2.对redis源码魔改
很多大厂就会这么做,会把开源组件【如redis,mysql】进行自定义修改,针对特定的业务需求
string的常见业务场景
1.热点数据缓存
redis的很大的一个作用就是做缓存!存储一些热点数据:

当用户访问某个数据的时候,服务器接收到请求:
就会先去缓存中进行搜索,如果命中了缓存直接返回数据
如果没有就需要去数据库中搜索:搜到了就写入缓存的同时返回数据,反之报错
缓存存储的都是一些热点数据:加快访问速度的同时保护数据库,不让数据库扛过多的并发
但是内存是有限的,redis能管理的数据肯定是不能一直增加:
所以redis必须有淘汰策略,以某种方法去进行淘汰key,这个方法是取决于业务需求的
常见的两种就是:
1)使用过期时间,让一些key在一定时间后过期
2)内存淘汰策略,使用一些淘汰算法,定期淘汰部分数据
2.统计用户数据
比如说某个视频,我想获取它的播放量,点赞数,粉丝数量等,就可以考虑使用redis进行存储
特别是一些热门的博主,他们经常被访问,使用的场景多
而redis可以做一个计数器,把一些热门的数据存储起来
但是,redis不适合做数据的处理!比如我想看看播放量前10的博主,这就很难办,这点反而是数据库干得好
所以,在企业开发中,经常是二者结合的使用:

缓存中有数据,要操作就操作,然后就返回;没有的采取数据库操作
如果要对某些数据进行统计处理,那就需要通过数据库来做
但是前提是:必须保证redis和mysql的数据一致性!否则引发很严重的问题:【如火车票超卖】
所以,redis的数据会定期向数据库,以异步的方式写入!
如果是同步写入的话:那就是redis操作一次,数据库就得操作一次,这效率十分低下!
要操作数据的时候,比如排序,过滤前,就强制将缓存数据同步数据库一次即可!
当然,真正成熟的系统:
肯定是不止这些皮毛的,还得配合一些防作弊机制,安全内容过滤,数据持久化等一系列问题!
3.验证码存储
还有就像是验证码的操作 :
我们可以给某个请求的设备设置一些限制策略:如一分钟内最多请求n次,单次验证码的有效时间
这个时候就可以用redis,存储x位数的验证码【类型为string】
只需要给key设置过期时间即可
4.Session会话存储
Session我们通常都是和Cookie进行联系的:
Cookie:浏览器端存储用户数据的机制
Session:服务器端存储用户数据的机制
在服务器端,用户的相关数据都是通过一个Session来进行存储
但是,随着访问量变大,架构变为分布式架构后,最大的问题就来了:

当【负载均衡器】分发请求给Web服务器的时候,Web服务器不知道这个用户的相关数据在哪里啊?
这一样会引发很严重的数据不一致问题!
所以,架构必须要进行升级:
可以采用redis进行存储Session,然后让所有的web服务器都从同一个redis节点取出Session数据:

这样后,所有的Web服务器都可以在同一个节点下存取Session,这就解决了上述的问题!

2079

被折叠的 条评论
为什么被折叠?



