Redis远程字典服务器(4)—— string类型详解

devtools/2024/11/13 11:35:11/

目录

一,string基本情况

二,string命令详解

2.1 set命令选项

2.2 setnx,setex

2.3 incr,incrby

2.4 decr,decrby

2.5 append拼接

2.6 getrange获取

2.7 setrange修改

2.8 strlen获取长度

2.9 总结

三,内部编码

四,string类型应用场景

4.1 缓存(cache)

4.2 计数(count)

4.3 会话(session)

一,string基本情况

  1. Redis中的字符串,直接就是按照二进制数据方式存储的,不会做任何的编码转换,存的是啥,取出来就是啥,这样就不仅仅能存文本数据了,整数,文本字符串,JSON,xml,甚至图片视频音频都可以存,但是很少存视频啥的,因为体积比较大
  2. 对于编码转换,我们在讲MySQL的时候,知道MySQL默认的字符集是拉丁文,插入中文就会失败,所以需要进行编码转换;但是Redis没有,所以Redis遇到乱码的概率更小
  3. 所以Redis对于string类型,限制了大小为512M,Redis单线程模型希望你进行的操作都能比较简单快速

二,string命令详解

2.1 set命令选项

前面说过,set命令后面还有一条很长的选项,现在就可以介绍下了:

  1. 方括号里面的EX,相当于在set创建键值对使设定过期时间,单位为秒,PX也是设置时间,单位是毫秒,中间的 “ | ” 表示 “ 或 ”,代表 EX 和 PX 只能同时存在一个:
  2. 后面方括号的NX和XX,其中NX表示如果key不存在就创建键值对,如果key存在就返回nil;XX是如果key存在就用新的value覆盖更新旧的value,如果key不存在就返回nil,一样的,“ | ”表示“ 或 ”,NX和XX只能用一个 
  3. “ FLUSHALL ”,这个命令清除当前Redis上所有的键值对,俗称“删库”,在学习阶段我们可以使用该命令快速清除旧的键值对,但是以后在公司里后,绝对绝对绝对不能使用该命令
  • get命令查询value时,只支持查字符串类型的value,如果value是其它类型,再使用get会返回错误
  • mset和mget的时间复杂度是O(N),N是你当前命令行给出的键值对的数量,所以可以认为是O(1) 

2.2 setnx,setex

这两个命令就是上面几个set包括选项的简写,那么为什么会有简写呢

  • 之所以这样搞,就是为了让操作“更符合人的直觉”,(使用的门槛更低,要记得东西更少)
  • 编程语言中,很多的关键词都是和自然语言相关的,后面我们去设置一些库,一些工具,写代码给别人用的时候,也尽量符合人们的直觉,不要设计得反直觉,俗称“反人类”

2.3 incr,incrby

这两个命令是对key的value做加法操作,其中incr是针对value + 1,incrby是针对value + n;所以这几个命令说是操作string,其实是在操作数字:

 

注意: 

  • 当value为其它类型或者为小数超过了64位,都会报错(64位相当于C++中的long long,Java中的long)
  • 当incr一个不存在的key时,会创建该key,并将value设置为1
  • incrby的n可以为负数,简单来说就是 “ +(-n) ” :

2.4 decr,decrby

decr 和 decrby 和上面的一样,只是变成了减法,其余规则和加法一样:

其实对于运算操作还有一个“ incrbyfloat ”,这个是针对浮点数的,而且这个没有decr版的,只能加上 负数 来实现减法,,然而以后我们很少使用浮点数去计数,所以这里了解一下就好啦~

上述的加法减法操作时间复杂度都是O(1),并且就算多个线程同时操作,也不会有线程安全问题 

2.5 append拼接

append是我们的老朋友了,C++用过很多,表示字符串拼接,在Redis这里的话,如果key存在,就把新value拼接到旧的value后面,如果key不存在,相当于set创建键值对(没法加选项)

然后是针对中文和编码的一些扩展: 

我们将value设置为中文,会返回6,而Redis的返回值是字节,而前面也说过Redis不会对字符做任何的处理,由于XShell的默认字符串编码是utf8,所以一个汉字的长度通常是3字节:

然后我们用get命令后,会显示如下结果:

可以看到我们的“你好”两个字变成了一串代码,这其实是因为Redis在存储时只按照二进制的方式存的,不会做任何的编码处理,所以get的时候读取到的也只有二进制数,然后将二进制数按照16进制转换就变成了我们看到的样子

其实我们可以把打印的这串结果复制一下,去百度随便找一个编码转换器,其实可以看到使用utf8编码转换后,依旧是“你好” 两个字:

再进一步,如果我们想让Redis直接给我把“你好”打出来,该咋操作呢?可以在启动Redis客户端时,带上 “ --raw ”,使Redis客户端能够将二进制数据尝试翻译:

  

2.6 getrange获取

这个命令表示 “ 获取字符串中指定范围的内容 ”,start和end就是要获取的字符串的起始位置和终止位置,具体可以参考C++的substr字符串分割函数,或者Java的substring函数:

  • Redis中指定的区间是闭区间,在编程的大圈中,区间大多都是“前闭后开”,但是也有像Redis这样的“前闭后闭”特殊情况
  • 正常下标都是从0开始的整数,但是Redis的下标是可以支持负数的,比如 -1 就是倒数第一个整数,下标为len - 1 的元素,这种允许下标为负数的机制和python一致
  • 但是如果字符串保存的是汉字,进行这种子串切分就不是完整的汉字了,C++中同样有该问题,但是Java不会,因为Java中字符串的基本单位是字符,C++中字符串的基本单位是字节
  • Java中的String 类会帮我们把汉字的编码转换都处理好,而C++对于汉字的处理就没那么完善,需要我们手动处理(推测原因可能是C++发展得比较早,对于中文没有较好的适配)

2.7 setrange修改

这个命令的作用就是“修改字符串具体位置的值”,命令选项中的“ offset ”也是我们的老朋友了,就叫做“ 偏移量 ”, 表示从第几个字节开始进行替换,后面的value就是要进行替换的新内容:

注意:

  •  修改后的value,会覆盖旧的,如果新的value比旧的长,会延长旧的
  • 如果当前value是中文字符串,再用setrange,会搞出问题的,会被解析成乱码
  • 当key不存在时,也会创建键值对,当offset为n时,会在最前面的位置凭空生成n字节,每个字节的内容是0x00,然后新value就会追加到后面(如果启动Redis时带了--raw选项,就不会显示 “ \x00 ”了):

2.8 strlen获取长度

这个很简单,就算获取value的长度,和上面部分命令的返回值的数一样,这里就不演示了哈,不过还是有几个地方需要注意:

  • 获取到的单位长度是字节,C++中字符串的长度就是以字节为单位,Java中字符串的长度以字符为单位,(Java中一个char == 2个字节,并且Java的char基于unicode这样的编码方式,就能表示中文等符号)
  • MySQL我们学过varchar(N),N的单位就是字符,MySQL中的字符,也是完整的汉字,这样的一个字符,可能是多个字节
  • utf8和Unicode是两种编码方式,Java中的char是unicode,是2字节,但是Java的String,用的是utf8,是3个字节,Java的标准库内部,在进行上述操作过程中,程序猿一般是感知不到编码方式的变换的
  • 所以C++一个汉字3个字节,Java是2字节

2.9 总结

命令执行效果

时间复杂度

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),n 是字符 串⻓度, 通常视 为 O(1
getrange key start end获取指定 key 的从 start 到 end 的部分值O(n),n 是字符 串⻓度, 通常视 为 O(1

三,内部编码

 字符串类型的内部编码主要有3种:

  • int:8个字节的长整型
  • embstr: <=39 字节的字符串(压缩字符串,适用于比较短的字符串)
  • raw:>39 字节的字符串 (普通字符串,适用于更长的字符串,只是单纯的持有字节数组)
  • Redis会根据当前值的类型和长度动态决定使用哪种内部编码实现

39这个数字,不是绝对的,一切还是要以具体业务为准,比如我们也可以将100个字节长度的value也用embstr来实现,但是有要求:

  1. 先看Redis是否提供了对应的配置项,可以修改39这个数字
  2. 如果没有提供配置项,我们就需要对Redis的源码进行魔改

很多大厂,都是自己造轮子,不用业界成熟的,因为开源的软件,往往考虑的是通用性,但是大厂往往会遇到一些刁钻的业务场景,所以需要针对很多的开源软件进行定制化

四,string类型应用场景

4.1 缓存(cache)

  • 整体的思路是,应用服务器访问数据库的时候,先查绚Redis,如果有,直接返回,如果没有就去MySQL去找,然后把该数据写进Redis再返回。Redis这样的缓存,经常用来存放热点数据(一个数据被用到了,那么有很高的概率会被重复用到,假设)
  • 问题:随着时间的推移,Redis里面的数据肯定是越来越多的 --> 所以我们可以设置过期时间,配合淘汰策略,清理过期的key,以后再详细介绍

4.2 计数(count)

计数功能最直白的例子就是:视频网站的视频播放次数 

  • 企业为啥老喜欢手机用户数据? --> 为了统计,进一步明确用户的需求 --> 根据需求进一步改进和迭代产品
  • Redis并不擅长数据统计,比如我要知道播放量前100的视频,Redis搞就很麻烦,但是用MySQL的话,一个sql语句就搞定了
  • Redis写入MySQL的步骤:异步,将播放量同步到其它数据源(异步的,不是来一个播放就立马写数据,因为那样做的话效率太低)

4.3 会话(session)

这个我们之前已经讲到过:Redis远程字典服务器(0)——分布式系统-CSDN博客

举个场景:

  1.  我去看病,医生给我做了检查开了一些药,然后让我“一周后”来复查
  2. 一周后我来了,但是医生换了一个,上一周的那个医生没上班,所以这个医生可能不了解我的情况
  3. 所以,这个医生就拿着我的医保卡一刷,在他的电脑上就出现了我之前的病例

针对上面的场景:

  1.  我是病人,相当于一个客户端,医生相当于服务器给我提供服务,由于病人可能会多次访问服务器,服务器就需要很好的了解病人的情况
  2. 而医生有多个,服务器也有多个,是会通过负载均衡来提供服务的,所以病人两次来看病可能是不同的医生
  3. 所以需要用一台服务器来单独存储病人的情况,叫做session服务器,在“分布式系统”博客已经讲过
  4. 这个记录病人的病例,诊断结果,治疗情况等,就是所谓的会话,是客户端和服务器在交互过程中产生的一些中间状态的数据;而且由于这些数据具有临时性,所以也可以用Redis来存

http://www.ppmy.cn/devtools/96395.html

相关文章

使用python-pptx修改幻灯片背景:设置或更改幻灯片的背景颜色和图片

哈喽,大家好,我是木头左! 一个美观、专业的背景可以让整个PPT看起来更加高级,更能吸引观众的注意力。那么,如何使用Python来修改PPT的背景呢?本文将介绍如何使用python-pptx库来设置或更改幻灯片的背景颜色和图片。 1. 安装python-pptx库 需要安装python-pptx库。可以使…

系统架构师(每日一练19)

每日一练 1.完整的软件系统需从不同视角进行描述&#xff0c;下图属于软件架构设计中的()&#xff0c;用于()视图来描述软件系统 。答案与解析 问题1 A.对象图 B.时序图 C.构件图 D.类图 问题2 A.进程 B.开发 C.物理 D.用户 2.关于模块化设计&#xff0c;()是错误的。答案与…

深入探索CANoe的CAPL语言

概述 在汽车电子和嵌入式系统开发领域&#xff0c;仿真和测试是确保功能正确性和性能标准的关键步骤。Vector公司的CANoe软件是这一领域的佼佼者&#xff0c;它提供了一个强大的平台&#xff0c;用于模拟、测试和分析汽车网络&#xff0c;特别是CAN网络。今天&#xff0c;我们…

Arduino开源四足蜘蛛机器人制作教程

视频教程&#xff1a;手把手叫你做四足蜘蛛机器人——1零件介绍_哔哩哔哩_bilibili 一、项目介绍 1.1 项目介绍 Arduino主控&#xff0c;图形化编程&#xff0c;趣味学习 Arduino nano开发板舵机扩展底板 4.8V可充电电池&#xff0c;支持Arduino C语言编程和米思齐图形化编程…

奥运科技观察:AI PC,如何成为当代体育精神的数字捍卫者?

作者 | 曾响铃 文 | 响铃说 数字孪生帮助体育馆建设、超高清直播……这届奥运会科技感拉满&#xff0c;几乎所有前沿技术都能在奥运的赛事运营中发现。 而AI大时代&#xff0c;AI如何帮助帮助奥运会顺利举办、如何帮助运动员拥有更好的表现&#xff0c;同样值得业界关注&…

宝塔面板部署webman项目+nginx反向代理

新建站点 新建一个站点&#xff0c;php版本选择纯净态即可&#xff0c;反正都是用不上的&#xff0c;域名填写你申请得到的域名 拉取代码 新建一个目录&#xff0c;然后将代码部署到本地 启动项目 推荐使用宝塔面板的进程守护管理器启动项目&#xff0c;其实就是用superviso…

Go语言 类继承

本篇文章主要内容为Go语言类继承介绍及类继承示例。 目录 继承 定义父类 类嵌套 定义学生类 赋值及调用 继承 定义老师类 赋值及调用 同名字段 访问权限 总结 继承 Go 语言中没有继承的概念&#xff0c;所以结构、接口之间也没有父子关系。 Go 语言提倡的是组合利…

How to run angular CICD on gitlab-runner of wsl?

前提文件 .gitlab-ci.yml, .dockerignore, ci-funcs.sh, Dockerfile, karma.conf.js, nginx.conf, nginx-custom.conf, sonar-project.properties 1.test.ts const context require.context(./app/pages, true, /\.spec\.ts$/); 2.sonar-project.properties sonar.sourcessrc/…