响应式网站和不响应式,浏览器网站,网站运营存在的问题,做网站九州科技【Redis_Day5】String类型 String操作String的命令set和get#xff1a;设置、获取键值对mset和mget#xff1a;批量设置、获取键值对setnx/setex/psetexincr和incrby#xff1a;对字符串进行加操作decr/decrby#xff1a;对字符串进行减操作incrbyfloat#xff1a;浮点数加… 【Redis_Day5】String类型 String操作String的命令set和get设置、获取键值对mset和mget批量设置、获取键值对setnx/setex/psetexincr和incrby对字符串进行加操作decr/decrby对字符串进行减操作incrbyfloat浮点数加/减一个汉字究竟占几个字节append字符串拼接redis中字符串也有下标getrange返回key对应的string的子串setrange替换字符串指定部分strlen获取字符串的长度字符串相关命令小结 flushall删库String内部编码String的应用场景缓存计数功能共享会话(Session) String
redis中的所有key都是字符串类型value也可能是字符串类型。
String类型的值可以是字符串包含⼀般格式的字符串或者类似JSON、XML格式的字符串可以是数字可以是整型或者浮点型甚⾄可以是⼆进制流数据例如图⽚、⾳频、视频等。但是⼀个字符串的最⼤值不能超过512MB。
redis内部存储字符串的时候完全是按照⼆进制流的形式保存的所以Redis是不会做任何编码转换的客户端传⼊的命令中使用的是什么字符集编码就存储什么字符集编码。 比如mysql8采用utf8mb4编码mysql存数据的时候会默认对数据按照ytf8mb4进行编码。redis存数据时不会这样redis内部没有设计字符集所以使用redis时遇到乱码的概率很小。
操作String的命令
在redis中操作不同类型的数据需要用不同的命令下面总结一些操作String类型数据的命令
set和get设置、获取键值对
通过set和get可以操作字符串String。
set和get的基础操作不再赘述。
总结set的用法 参考redis文档 SET key value [expiration EX seconds|PX milliseconds] [NX|XX] 其中 []相当于一个独立单元表示可选项可有可无 |是或者意思 []和[]之间可以同时存在 set后可以跟选项
set key1 value1 ex xxx (相当于set key1 value1和expire key xxx的结合优化后减少了网络通信的次数且保证了命令原子性)把键值对存到redis中并为该键值对设置过期时间为xxx。如果key1不存在创建新的键值对如果key存在让value1覆盖旧的value覆盖过程中可能会改变原来的数据类型此时原来key的ttl生存时间也会失效。同理set key1 value1 px xxx(相当于set key1 value1和pexpire key xxx的结合)set key1 value1 nx/xx:如果这条命令后加了nx或者xx nx表示如果key1已经存在返回nil本次设置无效如果key1不存在设置key1的值为value1并返回OK。 xx表示如果key1不存在返回nil本次设置无效如果key1存在用本次设置的value1覆盖之前设置的并返回OK。
nx是默认项。
总结get的用法 get只支持字符串类型的value。如果value是其他类型使用get获取就会出错。
比如用get获取list类型的value
mset和mget批量设置、获取键值对
相比于get和setmset和mget可以一次操作多组键值对。优点很明显减少网络通信的次数提高效率。
学会使⽤批量操作可以有效提⾼业务处理效率但是要注意每次批量操作所发送的键的数量也不是无节制的否则可能造成单⼀命令执⾏时间过⻓导致Redis阻塞。 总结mset的用法 mset key value [key value ...]一次性设置多个key的值。返回值永远是OK。
总结mget的用法 mget key [key ...]一次性获取多个key的值。如果对应的key不存在或者对应的数据类型不是string返回nil。 mset和mget的时间复杂度都是O(N)N是当前命令中key的数量。所以时间复杂度也就是O(1)。
setnx/setex/psetex
setnx key valuesetnx即加了nx选项的set命令。key存在设置失败key不存在设置成功。 setex 键 值 过期时间setex即加了ex选项的set命令。把键值对存到redis中并且设置过期时间过期时间的单位是秒。 psetex 键 值 过期时间psetex即加了px选项的set命令。过期时间的单位是ms。
incr和incrby对字符串进行加操作
incr针对value1 incrby针对valuen
总结incr的用法
incr keykey对应的value必须是整数8byte整数。返回值是value1之后的值。如果key对应的value不是⼀个整型或者范围超过了64位有符号整型则报错。 incr key(key不存在)incr操作的key如果不存在则视为key对应的value是0。
总结incrby的用法
incrby key n将key对应的string表⽰的数字加上n。 如果key不存在则视为key对应的value是0。如果key对应的string不是⼀个整型或者范围超过了64位有符号整型则报错。 incrby可以加负数。相当于decrby。
decr/decrby对字符串进行减操作
decr针对value-1 decrby针对value-n
decrdecrby和incrincrby的用法完全一样。
key5不存在
incrbyfloat浮点数加/减
decr、decrby、incr、incrby都只能算整数。 incrbyfloat针对String类型的value进行加一个小数或减一个小数操作。减一个小数相当于加上一个负的小数。vlalue可以是小数。
没有decrbyfloat这个命令
如果key不存在则视为key对应的value是0。如果key对应的不是string或者不是⼀个浮点数则报错。允许采⽤科学计数法表示浮点数。 decr、decrby、incr、incrby、incrbyfloat的时间复杂度都是O(1)。
一个汉字究竟占几个字节
如果编码方式是utf8一个汉字占3个字节。如果编码方式是unicode一个汉字占2个字节。
最典型的就是在java中char类型的单位是字符一个汉字是一个字符此时一个字符等于2个字节因为char用的是UnicodeString类型的单位也是字符一个汉字是一个字符此时一个字符等于三个字节因为String背后的编码方式utf8。在Java标准库中char和String之间的变化方式非常丝滑程序员感受不到。 mysql中的数据类型varchar(N)单位也是字符一个汉字是一个字符所以一个字符可能是多个字节。至于一个字符具体相当于多少个字节要看varchar(N)采用的编码方式。
C中字符串的单位是字节。
redis中字符串的单位是字节。但是redis内部没有设计任何字符集一个汉字占3个字节是怎么回事这是因为xshell终端默认的字符编码是utf8在xshell终端输入汉字后汉字先按照utf8编码的而一个汉字在utf8字符集中通常是3个字节所以在redis中一个汉字占三个字节。
每中编码方式的码表都不一样。同一个汉字使用的编码方式不同得到的对应值也不同。
append字符串拼接
字符串也支持一些常用的操作比如拼接获取/修改字符串的内容获取字符串的长度redis中支持这样的命令。
总结append的用法 append key value如果key已经存在并且是⼀个string命令会将value追加到原有string的后边。如果key不存在则效果等同于SET命令创建一个新的键值对。时间复杂度是O(1)。 返回值是追加完成之后String的长度。String长度的单位是字节。 get keys后显示的是用utf8编码后的“你好”。(客户端传⼊的命令中使用的是什么字符集编码就存储什么字符集编码。) 其中\x是转义字符不属于数据内容。 在启动redis客户端时加上--raw选项可以使redis客户端自动把二进制数据尝试翻译。
redis中字符串也有下标
redis中字符串也有下标第一个字符处于0下标。最后一个字符可以用-1下标表示。
getrange返回key对应的string的子串
总结getrange的用法
getrange key start end返回key对应的string的子串由start和end确定左闭右闭。start为0表示的是字符串第一个字符。使⽤负数表示倒数。-1代表倒数第⼀个字符-2代表倒数第⼆个其他的与此类似。超过范围的偏移量会根据string的长度调整成正确的值。 如果字符串中保存的是汉字此时进行子串切分很可能切出来的就不是完整的汉字了。
setrange替换字符串指定部分
总结setrange的用法
setrange key offset value 从下标offset开始用value覆盖字符串。返回值是替换后的新的字符串的长度。0表示的是字符串第一个字符。 如果当前key的value是一个中文字符串进行setrange容易出问题。就比如说一个汉字占三个字节但是只覆盖了这个汉字的前两个字节。如果key不存在 如下面例子key1不存在 \x是转义字符表示这是一个十六进制数据。\x00表示凭空生成一个字节这个字节里面的内容是0x00(0x00是16进制)。
strlen获取字符串的长度
总结strlen的用法
strlen key获取key对应的string的⻓度。当key存放的值不是string类型时报错。返回值是字符串的长度。如果key不存在返回0。
字符串相关命令小结 flushall删库
flushall清楚redis上的所有数据 也就是删库。
String内部编码
字符串类型的内部编码有3种 • int8个字节(64bit)的长整型。 • embstr小于等于39个字节的字符串。短字符串 • raw大于39个字节的字符串。(长字符串) Redis会根据当前值的类型和⻓度动态决定使用哪种内部编码实现。
redis存储小数本质上是把小数当做字符串来存储。这意味这每次进行算术运算都需要把字符串转换成小数运算结束后再把结果转回字符串保存。
String的应用场景
缓存
redis作缓存的时候常被用来存储“热点”数据。热点数据就是被高频使用的数据。不同场景下对高频的定义也不同。由于Redis具有⽀撑⾼并发的特性所以缓存通常能起到加速读写和降低后端压⼒的作⽤。
redismysql组成的缓存存储架构 假设把最近使用到的数据作为热点数据存储在redis中解释上面的场景 redis做缓存的时候应用服务器访问数据先查询Redis如果redis上数据存在就直接从redis上取数据交给应用服务器不继续访问mysql了。如果redis上数据不存在再读取mysql把读到的结果返回给应用服务器的同时把这个数据也写入到redis中。
但在上述场景中存在一个问题随着时间的推移有越来越多的key在redis上访问不到从而从mysql读取并写入redisredis中的数据会越来越多。 解决办法
把数据写到redis中的同时给这个key设置一个过期时间。redis在内存不足的时候提供了淘汰策略。
用伪代码模拟上述场景进一步理解String在其中的应用 redis用key-value存储用户信息 keyuser:info:uidvalue是String类型。 例如 keyuser:info:student01value经过序列化后的01用户对象字符串 keyuser:info:student02value经过序列化后的02用户对象字符串 value是json格式的StringJson格式的String类型也能存储机构化数据。 mysql用表user_info保存用户信息
//当用户发来请求时假设业务根据用户uid获取用户信息
//业务层
UserInfo getUserInfo(long uid) {//先查询redis假设用户信息保存在user:info:uid对应的键中String key user:info: uid;//从redis中获取对应的值String value 这里执行redis中的get key命令
//如果缓存命中(hit),即如果redis上存在这个信息if (value ! null) {// 假设我们的⽤⼾信息是按照 JSON 格式存储的UserInfo userInfo JSON反序列化(value);return userInfo;}
//如果redis上数据不存在再读取mysql把读到的结果返回给应用服务器的同时把这个数据也写入到redis中(miss)if (value null) {// 从mysql数据库中根据 uid 获取⽤⼾信息UserInfo userInfo MySQL执⾏SQL语句select * from user_info where uid uid// 如果mysql表中没有 uid 对应的⽤⼾信息if (userInfo null) {响应 404return null;}// 如果mysql表中有 uid 对应的⽤⼾信息//1. 将⽤⼾信息序列化成 JSON 格式String value JSON序列化(userInfo);//写⼊缓存为了防⽌数据腐烂rot设置过期时间为 1 ⼩时3600 秒Redis 执⾏命令set key value ex 3600//2. 返回⽤⼾信息return userInfo;}
}关于key的命名 与MySQL等关系型数据库不同的是Redis没有表、字段这种命名空间而且也没有对键名有强制要求除了不能使用⼀些特殊字符。但设计合理的键名有利于防止键冲突和项目的可维护性比较推荐的⽅式是使用**业务名:对象名:唯⼀标识:属性**作为键名。 例如 MySQL的数据库名为vs用户表名为user_info 那么对应的键名可以使用vs:user_info:6379、“vs:user_info:6379:name来表示如果当前Redis只会被⼀个业务使用可以省略业务名vs:”。 如果键名太长则可以使用团队内部都认同的缩写替代例如 user_info:6379:name可以被ui:6379:na代替。毕竟键名过长会导致Redis的性能明显下降的。
从redis中取出来的用户信息是String格式(JSON格式)通过JSON反序列化可以把它变成对象。 从mysql中取出来的用户信息是对象通过JSON序列化可以把转成字符串然后再存到redis中。
计数功能
许多应⽤都会使⽤Redis作为计数的基础⼯具它可以实现快速计数、查询缓存的功能同时数据可以异步处理或者落地到其他数据源。 例如使用Redis来记录视频网站的视频播放次数用户每播放⼀次视频相应的视频播放数就会⾃增1。 redis并擅长数据统计比如再上述场景中统计播放量前100的视频有哪些基于redis完成这个任务很麻烦。相比之下如果是mysql存储上述数据一个sql命令就完成了。但是用mysql记录遇上高并发场景又容易挂。
解决办法把redis上统计相关的数据通过异步的方式同步到统计数据仓库上统计数据仓库可能是mysqlhdfs等。 异步方式不是redis收到xxx个播放请求就立即把它也写到仓库中而是根据仓库的接收能力把数据持续地写入到仓库中只要保证最终能把数据都正确写入到仓库中即可。
实际中要开发⼀个成熟、稳定的真实计数系统要面临的挑战远不止如此简单防作弊、按照不同维度计数完播率等、避免单点问题数据备份、数据持久化到底层数据源等。
共享会话(Session)
会话是客户端和服务器再交互过程中产生的一些专属于该客户端的中间状态的数据。 cookie是浏览器的会话存储机制session是服务器的会话存储机制。 cookie和session中都是用键值对存储数据的。
为了更好的理解共享会话(Session)先来看看**服务器之间不共享会话(session)**的情况 session分散存储 上面是一个分布式Web服务在这个服务中用户的Session信息例如用户登录信息保存在各自的服务器中但这样会造成⼀个问题出于负载均衡的考虑分布式服务会将用户的访问请求均衡到不同的服务器上并且通常无法保证用户每次请求都会被均衡到同⼀台服务器上这样当用户刷新⼀次访问是可能会发现需要重新登录这个问题是用户⽆法容忍的。 如何解决上述问题
用redis集中管理session即服务器之间通过redis共享会话session。 以上是Redis的字符串数据类型可以使⽤的三个典型场景其适⽤场景远不止于此。 总结两个xshell热键 ctrls冻结当前画面。 ctrlq解除冻结。 下次见~