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

[Redis] Redis中的String类型

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(96平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. Redis中的String的相关操作
    • 1.1 字符串的存储方式
    • 1.2 关于string的常见命令
    • 1.3 string的其他命令
    • 1.4 字符串指令小结
  • 2. String的内部编码方式
  • 3. string类型的具体应用场景
    • 3.1 缓存功能
    • 3.2 计数功能
    • 3.3 共享会话(session)
    • 3.4 手机验证码

1. Redis中的String的相关操作

1.1 字符串的存储方式

Redis中,key的数据类型是一个string,但是value的数据结构可以是多种多样的,我们在之前的文章中介绍过.这里不再赘述.
这里我们需要注意的是.Redis中存储string的方法和java中,MySQL中的存储方式并不一样.Redis中存储字符串的时候,会直接存储字符串的二进制数据,不会对二进制数据做出任何的编码转换,存入的是什么,取出的还是什么,但是java和MySQL不一样,java中存储字符串的时候会涉及到编码方式的问题,MySQL中,字段不可以插入中文,这是因为MySQL的默认编码方式是拉丁文,与汉字不兼容.
既然Redis中可以存储二进制数据,那么就不仅仅可以存储字符串,还可以存储一些其他的二进制数据,比如图片,视频,音频等.
但是Redis是单线程的,Redis为了保证存储于获取数据的高效性,一般不可以存储占据空间太大的数据,默认情况下是不超过512M.
在这里插入图片描述

1.2 关于string的常见命令

  • set
    在前面的章节,我们曾经介绍过set这个命令,但是之前的哪个set命令还不是最全面的,set除了可以设置键值对之外,还可以对键值对设置其他的属性.
    set key value [ex seconds|px milliseconds] [nx|xx]
    • 其中ex是为当前键值对设置过期时间,单位是秒,相当于set key value; expire key seconds,也可以使用px设置毫秒级别的过期时间.
    • nx是当前如果当前key存在,则不设置当前的key,直接返回nil,如果不存在,则设置,而xx与nx的效果恰好相反,当key存在的时候,覆盖掉当前的key,如果当前key不存在,则不设置.
  1. 夹带选项的set指令可以被后续的Redis命令取代,比如setex,setnx,setpx等.
  2. 如果使用xx选项,可能会改变原来value的数据类型,原来key的过期时间也会被覆盖掉
  3. 原地离职小技巧: 如果想要删除Redis服务器中的所有键值对,可以使用flushall指令.

代码演示:

127.0.0.1:6379> set key1 value1 ex 10
OK
127.0.0.1:6379> ttl key1
(integer) 6
127.0.0.1:6379> ttl key1
(integer) 5
127.0.0.1:6379> ttl key1
(integer) 2
127.0.0.1:6379> ttl key1
(integer) -2
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> set key1 value2 nx
(nil)
127.0.0.1:6379> set key1 value2 xx
OK
127.0.0.1:6379> get key1
"value2"
127.0.0.1:6379> set key2 value1 ex 20
OK
127.0.0.1:6379> set key2 value3 xx
OK
127.0.0.1:6379> ttl key2
(integer) -1 //覆盖掉了原来的过期时间
  • get
    这个指令和我们之前提到过的get指令没有什么区别,==唯一需要注意的一点就是,获取key对应的value的时候,value必须是string类型的数据,否则就会报错.
127.0.0.1:6379> lpush key val1 val2 val3
(integer) 3
127.0.0.1:6379> get key
(error) WRONGTYPE Operation against a key holding the wrong kind of value

这里我们创建了一个value为列表的键值对,我们发现在用get访问的时候,程序出现了报错.

  • mset
    用来一次性设置多个键值对.
127.0.0.1:6379> mset key1 val1 key2 val2 key3 val3
OK
127.0.0.1:6379> keys *
1) "key2"
2) "key1"
3) "key3"
  • mget
    用来一次性获取多个key对应的value.
127.0.0.1:6379> mget key1 key2 key3
1) "val1"
2) "val2"
3) "val3"

我们在前面的章节的exists指令提到过,我们能把多次查询合并到一步,我们一般不会使用分开好几步的查询.这样一方面会比较占用网络资源,另一方面会让网络请求拖慢Redis的执行性能.
在这里插入图片描述
在这里插入图片描述
但是我们使用上面两个请求的时候,也不可以一次性设置太多的key和value或者是一次性获取太多的value.否则就会让Redis服务器发生阻塞.

  • setnx
    set key value nx效果一样.key存在的时候不创建,不存在的时候才创建.
127.0.0.1:6379> keys *
1) "key2"
2) "key1"
3) "key3"
127.0.0.1:6379> setnx key1 value1
(integer) 0
127.0.0.1:6379> get key1
"val1"
  • setex
    setex key seconds valueset key value ex seconds效果一样.为键值对设置过期时间.这里要注意一下setex的语法格式,先写key,再写过期时间,再写value.
127.0.0.1:6379> setex key4 10 value4
OK
127.0.0.1:6379> ttl key4
(integer) 5
127.0.0.1:6379> ttl key4
(integer) 4
127.0.0.1:6379> ttl key4
(integer) 2
127.0.0.1:6379> ttl key4
(integer) 0
127.0.0.1:6379> ttl key4
(integer) -2
  • incr
    incr key
    针对某一个key的value+1.如果这个key的value不是64位的整型,则报错.如果这个key不存在的话,则创建这个key,其中value的值默认为0,之后对value+1.这个操作的返回值就是这个key的value+1之后的值.
127.0.0.1:6379> set key1 1
OK
127.0.0.1:6379> incr key1
(integer) 2
127.0.0.1:6379> incr key2 
(integer) 1
127.0.0.1:6379> mget key1 key2
1) "2"
2) "1"
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> incr key1
(error) ERR value is not an integer or out of range
  • incrby
    incrby key increament
    针对某个key的value+指定的值.如果这个key的value不是64位的整型,则报错.如果这个key不存在的话,则创建这个key,其中value的值默认为0,之后对value+指定值.这个操作的返回值就是这个key的value+指定值之后的值.
127.0.0.1:6379> mget key1 key2
1) "2"
2) "1"
127.0.0.1:6379> incrby key2 7
(integer) 8
127.0.0.1:6379> incrby key1 2
(error) ERR value is not an integer or out of range
  • decr
    decr key
    针对某一个key的value-1.如果这个key的value不是64位的整型,则报错.如果这个key不存在的话,则创建这个key,其中value的值默认为0,之后对value-1.这个操作的返回值就是这个key的value-1之后的值.
127.0.0.1:6379> incrby key2 7
(integer) 8
127.0.0.1:6379> decr key2 
(integer) 7
127.0.0.1:6379> decr key3
(integer) -1
127.0.0.1:6379> get key3
"-1"
127.0.0.1:6379> decr key1 
(error) ERR value is not an integer or out of range
  • decrby
    decrby key decreament
    针对某个key的value-指定的值.如果这个key的value不是64位的整型,则报错.如果这个key不存在的话,则创建这个key,其中value的值默认为0,之后对value-指定值.这个操作的返回值就是这个key的value-指定值之后的值.
127.0.0.1:6379> decrby key2 1
(integer) 6
127.0.0.1:6379> decrby key4 3
(integer) -3
127.0.0.1:6379> decrby key1 2
(error) ERR value is not an integer or out of range
  • incrbyfloat
    incrbyfloat key increament
    将key对应的string表示的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值如果key不存在,则视为key对应的value是0。如果key对应的不是一个浮点数(或整数),则报错。允许采用科学计数法表示浮点数.
127.0.0.1:6379> set key1 1
OK
127.0.0.1:6379> INCRBYFLOAT key1 0.5
"1.5"
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> INCRBYFLOAT key2 0.5
(error) ERR value is not a valid float
127.0.0.1:6379> INCRBYFLOAT key1 -0.7
"0.8"
127.0.0.1:6379> INCRBYFLOAT key -0.5
"-0.5"

[注意] 这里的小数,Redis在保存的时候,在底层实际保存的是embstr,在Redis中并没有浮点型这样的数据类型.

127.0.0.1:6379> object encoding key1
"embstr"

1.3 string的其他命令

  • append
    append key value
    给指定key对应value拼接一个字符串,如果key已经存在,需要保证key对应的value是一个string类型的.如果这个key不存在,效果相当于set.
127.0.0.1:6379> append key2 aaaaa
(integer) 11
127.0.0.1:6379> get key2
"value2aaaaa"
127.0.0.1:6379> append key3 bbbbb
(integer) 5
127.0.0.1:6379> get key3
"bbbbb"
127.0.0.1:6379> append key1 ccccc
(integer) 8
127.0.0.1:6379> get key1
"0.8ccccc"
127.0.0.1:6379> set key4 7
OK
127.0.0.1:6379> append key4 ccccc
(integer) 6
127.0.0.1:6379> get key4
"7ccccc"

[注意]

  1. 当key对应的value保存的是一个整数,或者是一个小数的时候,别看是一个数字,实际Redis在保存他们的时候,同样是把他们当做字符串来看待的.
  2. 这里append的返回值是增加后的字符串的字节数,而不是字符数,下面我们使用汉字来说明一下这个问题.
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> set key1 你好
OK
127.0.0.1:6379> get key1
"\xe4\xbd\xa0\xe5\xa5\xbd"

这里我们看到Redis在保存汉字的时候,是已汉字的二进制方式来保存的,这也印证了我们上面所提到的,Redis保存string的时候,没有经过字符串编码,而是直接保存二进制数据."你好"两个汉字是6个字节.

127.0.0.1:6379> append key1 你好
(integer) 12

我们在原来字符串的基础上又一次拼接了一个"你好".返回的字符串长度是12字节.
那么如何让Redis显示汉字而不是汉字的16进制编码呢?我们可以在启动Redis的时候,使用redis-cil --raw指令来打开redis.

root@iZ2zeh2c69p4ax5heci8wmZ:~# redis-cli --raw
127.0.0.1:6379> get key1
你好你好
  • getrange
    getrange key start end
    在指定key的[start,end]区间(两边都是闭区间),截取一段字符串.有点像java中的substring()方法.
    其中redis的getrange操作与python一样是支持负数下标的,其中-1表示倒数第一个字符串.-2表示倒数第二个字符串.
127.0.0.1:6379> set key2 helloworld
OK
127.0.0.1:6379> getrange key2 0 -1
"helloworld"
127.0.0.1:6379> getrange key2 1 4
"ello"

[注意]
这里截取的时候,start和end依然指的是字节数.所以这里我们不建议使用getrange命令来截取汉字.因为汉字是汉字编码的16进制存储的,如果我们的redis是以–raw的方式打开的,截取出来的汉字很可能是一堆乱七八糟的东西.

127.0.0.1:6379> get key2
你好
127.0.0.1:6379> GETRANGE key2 1 -2
½ 
  • setrange
    setrange key offset value
    将指定key从第offset(这个叫做偏移量,MySQL中也有这个字段)字节开始的地方设置为指定字符串.返回设置之后字符串的长度.
127.0.0.1:6379> set key3 value
OK
127.0.0.1:6379> setrange key3 2 aaaaaaaa
10
127.0.0.1:6379> get key3
vaaaaaaaaa
  • strlen
    strlen key
    获取指定key对应value的字节长度.
127.0.0.1:6379> get key3
vaaaaaaaaa
127.0.0.1:6379> get key2
你好
127.0.0.1:6379> strlen key2
6
127.0.0.1:6379> strlen key3
10

1.4 字符串指令小结

在这里插入图片描述

2. String的内部编码方式

这个话题我们在上一篇文章中提到过

  • raw
    这个是最基本的字符串,类似与Java中的byte[ ]数组.
  • int
    redis有时会实现一些计数的功能,当value是整数的时候,redis就会直接用int类型来保存.
  • embstr
    当字符串比较短的时候,redis就会把字符串优化为embstr.

有的资料上会写当字符串超过39字节的时候会转换为raw,在39字节以下时候,就是embstr,这里不建议大家去记忆这样具体的数字,因为这个是可以根据具体的业务场景来修改的.

3. string类型的具体应用场景

3.1 缓存功能

其中Redis作为缓冲层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用
在这里插入图片描述
具体流程:
在应用服务器访问数据的时候,首先访问的是缓存(redis)的数据,如果redis中存在对应的数据,则返回给应用服务器.如果redis中不存在,则去存储层查询(MySQL),如果存在,则返回给应用服务器,同时保存在缓存(redis)中.如果MySQL中也不存在,直接给应用服务器返回错误码.
上述的过程存在一个明显的问题,就是在这种情况下,redis的数据会越积越多.针对这种情况,redis会给其中的一些键值对设置过期时间,也在内存不足的情况下提供了内存淘汰的策略.

3.2 计数功能

许多应用都会使用Redis作为计数的基础工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源.
假如我们需要统计一个视频的播放次数,如果直接对MySQL中的数据进行操作的话,开销会非常大,这时候我们就引入了redis来帮我们计数.但是如果直接使用redis来统计数据的话,这也不是redis擅长的领域,统计的工作还是需要交给MySQL来做.所以在这个过程中redis和MySQL是相辅相成的.
在这里插入图片描述
在一个视频被播放的时候.redis就会给对应的视频id的播放次数+1,之后会异步同步到统计数据仓库中,这里的异步同步指的是,数据不是立即同步过去的,而是每隔一段时间对数据进行同步,这样会在某种程度上减小统计数据仓库的开销.

实际中要开发⼀个成熟、稳定的真实计数系统,要⾯临的挑战远不⽌如此简单:防作弊、按照不同维度计数、避免单点问题、数据持久化到底层数据源等

3.3 共享会话(session)

我们在实际开发的过程中,系统可能是分布式的,一个系统可能会有多台服务器.在用户访问一个应用的不同板块的时候,可能会访问到不同的服务器,这时候不是每一个服务器都保存着这个用户session.如果在用户访问其他服务器的时候,就需要用户重新登录.我们如果对session采用分散存储的方式:
在这里插入图片描述
如果我们在上述方案的基础上引入redis.redis就可以对用户的session数据进行集中统一管理.这种情况下,无论用户被均衡到哪台Web服务器上,都集中从Redis中查询、更新Session信息.
在这里插入图片描述

3.4 手机验证码

用户在登录的时候,为了保证用户账号的安全,我们会使用验证码.当用户登录的时候,redis就会在服务器中保存一个与用户对应的验证码,这个验证码具有过期时间(比如在5分钟内有效).在用户输入验证码之后,会从redis中查询对应的键值对,校验用户的验证码.
当然为了用户反复接收验证码,导致redis压力过大,一般规定在一分钟之内,最多接收一次验证码,如果手机没有验证码,可以尝试在一分钟之后重新获取验证码.
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • jantic/DeOldify部署(图片上色)附带Dockerfile和镜像
  • c#语言写一个数组排序函数
  • DApp开发入门指南:从概念到实践
  • NX二次开发—批量导出点工具
  • Java高级Day40-QQ项目全代码
  • 物联网之PWM呼吸灯、脉冲、LEDC
  • 【Oracle篇】全面理解优化器和SQL语句的解析步骤(含执行计划的详细分析和四种查看方式)(第二篇,总共七篇)
  • memmove函数的使用与模拟实现
  • 基于人工智能的智能语音助手
  • DMDPC单副本集群安装
  • HarmonyOS开发实战( Beta5.0)滑动视频自动播放案例实践
  • Caffenie配合Redis做两级缓存,Redis发布订阅实现缓存一致更新
  • 利士策分享,在延长退休背景下,应该如何合理的规划退休生活?
  • openstack之glance介绍
  • 数据库-基本操作(一)
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • 2017-09-12 前端日报
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • css的样式优先级
  • ECMAScript6(0):ES6简明参考手册
  • ES6之路之模块详解
  • React+TypeScript入门
  • Sublime text 3 3103 注册码
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 电商搜索引擎的架构设计和性能优化
  • 分布式事物理论与实践
  • 构建二叉树进行数值数组的去重及优化
  • 观察者模式实现非直接耦合
  • 如何设计一个微型分布式架构?
  • 一个完整Java Web项目背后的密码
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​浅谈 Linux 中的 core dump 分析方法
  • !!java web学习笔记(一到五)
  • # AI产品经理的自我修养:既懂用户,更懂技术!
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #include到底该写在哪
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (1)常见O(n^2)排序算法解析
  • (day 12)JavaScript学习笔记(数组3)
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (Java入门)学生管理系统
  • (二)构建dubbo分布式平台-平台功能导图
  • (分享)自己整理的一些简单awk实用语句
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (十八)Flink CEP 详解
  • (图)IntelliTrace Tools 跟踪云端程序
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)重识new
  • ***利用Ms05002溢出找“肉鸡
  • .cn根服务器被攻击之后
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考