当前位置: 首页 > news >正文

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

目录

一,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来存

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 周记-2024年第32周8.5~8.11:北京出差,拒绝羞怯
  • 《大语言模型:原理与工程实践》大模型入门必读书籍,PDF版整理好了
  • Linux线程基础学习记录
  • 仅12%程序员担心被AI取代 62%开发者在使用AI工具
  • 贝莱德与摩根大通的最新季度持仓分析
  • 一个能减少重绘的属性?分享 1 段优质 CSS 代码片段!
  • html+css+js网页设计 作业歌帝梵官网首页1个页面6个js效果
  • C#中的多线程
  • 数字化营销在公域场景中的无限可能
  • 超详细!!!electron-vite-vue开发桌面应用之Electron Forge打包项目(三)
  • 作业08.16
  • excel 2019版本的index match搜索功能
  • 数据结构-查找
  • python-NLP:4句法分析
  • 共塑AI新篇章 | 云轴科技ZStack亮相2024中国操作系统产业大会
  • 「面试题」如何实现一个圣杯布局?
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • Hibernate最全面试题
  • Java反射-动态类加载和重新加载
  • Just for fun——迅速写完快速排序
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Python中eval与exec的使用及区别
  • Xmanager 远程桌面 CentOS 7
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 分布式事物理论与实践
  • 关于 Cirru Editor 存储格式
  • 前端知识点整理(待续)
  • 设计模式(12)迭代器模式(讲解+应用)
  • 使用 QuickBI 搭建酷炫可视化分析
  • 微信小程序填坑清单
  • 学习HTTP相关知识笔记
  • 原生js练习题---第五课
  • 正则与JS中的正则
  • Python 之网络式编程
  • ​​​​​​​​​​​​​​Γ函数
  • #《AI中文版》V3 第 1 章 概述
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #前后端分离# 头条发布系统
  • (7)svelte 教程: Props(属性)
  • (8)STL算法之替换
  • (function(){})()的分步解析
  • (JS基础)String 类型
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (强烈推荐)移动端音视频从零到上手(上)
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (一) 初入MySQL 【认识和部署】
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • (转)母版页和相对路径
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • ./configure、make、make install 命令
  • .gitignore文件---让git自动忽略指定文件
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景