Redis中的string类型

string介绍

  • Redis中的key都是字符串,value的类型是存在差异的
  • Redis中的字符串,直接就是按照二进制数据的方式存储的(不会做任何的编码转换,存的是啥,取出来就还是啥),不仅仅可以存储文本呢数据,还可以存储整数,普通的文本字符串,JSON,xml,二进制数据
  • 但是对于音频视频来说,体积可能会比较大,Redis对于string类型,限制了大小最大值,并且Redis还是单线程模型,希望进行的操作都是短平快的类型,访问音视频会慢
  • 对于MySQL,默认字符集是拉丁文,插入中文,就会失败;但是对于redis是没有这些限制的,插入什么,取出来就是什么;一般来说redis取出的字符不会是乱码,除非是编码对不上

string的常用命令

string的两个关键命令set和get

  • set key value ex 10还可以使用px 毫秒
  • nx-如果key不存在,才设置;如果key存在,则不设置(返回nil)

xx-如果key存在,才设置(相当于更新key的value);如果key不存在,则不设置(返回nil)

还有一些命令

setnx,setex,setpx

redis给出的文档说明:一个[]相当于一个独立的单元,表示可选项

其中|表示“或者”的意思,多个只能出现一个

[]和[]之间,是可以同时存在的

set key value

expire key 10

两次命令进行打包,可以说是原子操作

如果key不存在,创建新的键值对

如果key存在,则是让新的value覆盖旧的value,可能会改变原来的数据结构

原来这个key的ttl(生存时间)也会失效

一个有趣的技巧,清除redis上所有的数据~删库

flushall 可以把redis上所有的数据带走~~

get

语法较为简单,也就是get key获得value,对于get来说只支持获得字符串类型的value,如果value是其他类型,那么就会出错

mset

mget

mset和mget能够一次操作多组键值对

一下操作很多key的网络通信成本比一次通信操作一个key的成本更低

虽然可以使用mset和mget提高效率,但如果一次请求太多可能会堵住,所以要适量

mset和mget的时间复杂度均为O(N),这个N并不是所有key的数量,而是要操作key的个数,可以认为时间复杂度为O(1)

setnx

setnx表示不存在才能设置,存在则设置失败

设置超时时间,单位是秒,redis-cli会有自动补全

psetnx

设置key的过期时间,单位是毫秒

这三个命令均是对set进行封装,进行缩写,之所以这样写,就是为了操作更符合人的直觉,使用者的门槛月底,要背的东西越少

incr

incr-针对value+1

此操作的返回值就是+1之后的值

此时key对应的value得是整数

value的值也不可以很大

范围是8个字节也就是2^64,相当于C++中的long long,Java中的long

如果incr操作的value不存在,那么就会创建一个key-value键值对

incrby

incrby-针对value+n

同理若是字符串非常大,则会报错,若是针对不存在的值,也会创建一个新的键值对结构

若是增加一个负数可以不?可以,那还要decrby干啥呢?答案就是符合直觉 

decr

decr-针对value-1

和incr的用法一致,且相互对应的注意事项也是一致的

和incr一致,也会产生新的键值对

decrby

decrby-针对value-n

同样和incrby的用法一致

同样也可以 - (-10) 为了符合直觉

incrbyfloat

incrbyfloat-针对value+/-小数

针对浮点数作处理,这里并没有对应的decrbyfloat

只能用加上负数的形式实现减法,虽然此处没有减法版本的浮点数操作,但是redis本身就对整数情有独钟,所以无可厚非啦~

上述操作的时间复杂度为O(1),因为只对某个key所对应的value进行计算

由于redis处理命令的时候,是单线程模型,多个客户端同时针对同一个key进行incr操作,不会引起“线程安全”问题

字符串也支持一些常用的操作,拼接/获取/修改字符串的部分内容,获取字符串长度

append

使用append命令

返回值是字符串整体的长度,单位是字节,redis不会对字符编码做任何处理(redis不认识字符,只认识字节),XShell终端默认的编码方式是utf8,那么一个汉字的长度是3个字节

如果append一个不存在的key,那么就会创建一个新的键值对

获得的value是一个什么?是一个原始的utf8编码所表现出来的

网站

有没有什么办法可以让redis客户端展示”你好哈哈“这几个字符呢?

在启动redis客户端的时候,加上一个--raw这样的选项就可以使redis客户端能够自动地把二进制进行翻译

不小心按到了ctrl+s怎么办,一个是重新启动,另一个就是ctrl+q,因为ctrl+s是冻结画面,ctrl+q就是取消冻结

此时发现可以让终端尝试翻译,此时成功了

getrange

获取字符串中的字串,在C++中叫做stu::substr,在Java中叫做String.subString

图中的start end是我们要传的参数

redis中指定的区间是闭区间,C++和Java中谈到一个区间,大多都是前闭后开

正常下标都是从0开始的整数,redis的下标是可以支持负数的,-1是倒数第一个元素,下标为len - 1的元素

如果是汉字,切出来就不一定是原来的完整汉字了

切出来的不一定在utf8编码表上查出什么来

上述问题在C++中同样存在,Java中就没事,Java中字符串的基本单位,是字符,占两个字节

C++中字符串的基本单位是字节;Java中相当于String帮我们把汉字的编码转换都处理好了

setrange

把字符串对应的子串进行修改

offset-偏移量(从第几个字节开始进行替换,结束看value的长度)

value-要修改的字符

返回值是替换之后新的字符串的长度

如果当前value是一个中文字符串,进行setrange的时候可能会弄出问题

如果给一个未创建的key所对应的value进行转换,则会创建一个新的键值对结构

凭空多生成一个字节,也就是\x00

strlen

获取到字符串的长度,单位是字节

C++中,字符串的长度本身就是用字节为单位,Java中,字符串的长度则是以字符为单位

MySQL中的varchar(N),N单位就是字符,MySQL中的字符也是完整的汉字

Java中的char一个汉字占两个字节(unicode),Java中的String则是一个汉字占三个字节(utf8)

Java标准库的内部进行上述操作的过程中,我们一般感受不到编码方式的转换的

当value存放的类似不是string时,报错

string命令总结

指令作用的效果时间复杂度
set key value设置指定的key-value结构O(1)
get key获取key的值O(1)
del [key ...]删除指定的keyO(K)
mset key value [key value ..]批量设置指定的key和valueO(K)
mget key [key ..]批量获取key的值O(K)
incr key指定的key的值+1O(1)
decr key指定的key的值-1O(1)
incrby key n指定的key的值+nO(1)
decrby key n指定的key的值-nO(1)
incrbyfloat key n指定的key的值+nO(1)
append key value指定的key的值追加valueO(1)
strlen key获取指定key的值的长度O(1)
setrange key offset value覆盖指定key的从offset开始的部分值O(N)
getrange key start end获取指定key的从start到end的部分值O(N)

string内部的编码:

  • int:64位/8个字节的长整型
  • embstr:压缩字符串,小于等于39个字节的字符串
  • raw:普通字符串,适用于更长的字符串大于39个字节的字符串
  • 使用object encoding key来判断编码方式

某个业务场景,有很多很多的key,类型都是string,但是每个value的string长度都是100左右

更关注与整体的内存空间,因此这样的字符串使用embstr来存储也不是不能考虑

上述效果具体怎么实现?

  • 先看redis是否提供了对应的配置项,可以修改39这个数字
  • 如果没有提供配置型,就需要针对redis源码进行魔改

使用redis存储小数本质上还是当作存储字符串,小数进行字符运算,都需要将字符串转换为小数,进行运算,结果再转换位字符串

string类型的应用场景

作为缓存

整体思路:应用服务器访问数据的时候,先查询redis,如果redis上数据存在,就直接从redis取数据交给应用服务器,不继续访问数据库了;如果redis上数据不存在,再读取MySQL,把读到的结果,返回给应用服务器,同时,把这个数据也写入到redis中

redis这样的缓存,经常用来存储”热点“数据,高频被使用的数据,结合业务场景有很多种方式

刚才描述的过程相当于是把最近使用到的数据作为热点数据(暗含了一层假设,某个数据一旦被使用到了,那么很可能在最近一段时间会被反复用到)

上述策略存在一个明显的问题,随着时间的推移,肯定是会有越来越多的key在redis上访问不到

从而从MySQL读取并写入redis了,此时redis中的数据不是就越来越多吗?

  • 在把数据写给MySQL的同时,给这个key设置一个过期时间
  • redis也在内存不足的时候,提供了淘汰策略

计数功能-记录视频播放次数

redis并不擅长数据统计,比如想在上述的Redis中统计播放量前100的视频有哪些,基于Redis搞就很麻烦,相比之下,如果是MySQL来存储上述数据,一个sql就搞定了


上述的异步方式同步其他数据源:写入统计数据仓库的步骤,异步的:不是说来一个播放请求,这里就必须马上写一个数据

共享会话-Session分散存储

Session(服务器存储数据的机制)

Cookie(浏览器存储数据的机制)

对于两种机制可以使用学生卡与服务器存储学生的数据来理解

Session

当学生使用学生卡登录学校系统时,系统会创建一个学生档案,记录学生的个人信息、课程表、成绩等。这个档案存储在学校的服务器上,而不是在学生卡上。

Cookie

当学生使用学生卡登录时,学校系统会在学生卡上贴一个标签(Cookie),这个标签包含了一些基本信息,比如学生的ID和一些设置。每次学生使用学生卡时,系统通过读取这个标签来识别学生。
 

如果每个应用服务器,维护自己的会话数据,此时彼此之间不共享,用户请求访问到不同的服务器上,就可能会出现一些不能正确处理的情况了

此时所有的session数据都被各个服务器共享了

手机验证码

  1. 生成验证码-用户输入手机号,点击获取验证码(限制一分钟之内,最多获取5次验证码)
  2. 检查验证码-把短信收到的验证码这一串数,提交到系统中,系统进行验证验证码是否正确
  • 可以借助redis来实现限制一分钟之内,最多获取5次验证码
  • 可以使用incr和ex命令来设置一分钟之内设置发5次验证码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值