Hello , 各人好 , 这个专栏给各人带来的是 Redis 系列 ! 本篇文章给各人教学的是 Redis 中 string 范例的相干内容 , 我们会从常见下令、底层编码方式、应用场景三方面给各人先容
本专栏旨在为初学者提供一个全面的 Redis 学习路径,从底子概念到实际应用,资助读者快速把握 Redis 的使用和管理本领。通过本专栏的学习,可以大概构建坚固的 Redis 知识底子,并可以大概在实际学习以及工作中机动运用 Redis 办理题目 .
专栏地点 : Redis 入门实践
正文开始
我们现在谈到的数据范例 , 都是针对 value 来说的
Redis 中的字符串 , 直接就是按照二进制数据的方式来存储的 , 我们可以变相的将 string 视为字节数组
底层不会做任何的编码转化 , 也就是说存进去的是什么 , 取出来的就是什么 .
那 Redis 的字符串不光可以存储文本数据 , 它还可以存储整数、JSON、xml、二进制的数据 (图片 / 视频 / 音频) …
但是视频 / 音频体积大概会比力大 , 而 Redis 对于 string 范例 , 限定了巨细最大是 512M
那 Redis 他的底层是不会做任何的编码转换的
我们之前在学习 MySQL 的时间 , 默认的字符集是拉丁文 , 插入中文就会失败 .
而 Redis 存进去什么就是什么 , 直接取出来即可 , 就不消再判定字符集等等
一 . 常见下令
1.1 set
set 的语法 : set key value [ex 超时时间(秒) | px 超时时间(毫秒)] [nx | xx]
Redis 官方文档特殊符号的分析 :
[]就相称于一个独立的单位 , 表现可选项 (可有可无)
| 表现大概 , 多个条件之间只能出现一个
[]和[]是可以同时存在的
比如 我们的这一条指令 : set key value ex 10 , 他就相称于这两条指令
- set key value
- expire key 10
别的 , nx 指的是如果 key 不存在 , 才去设置 ; 如果 key 存在 , 则不去设置 (返回 nil)
xx 指的是如果 key 存在 , 才去设置 value (相称于更新利用) ; 如果 key 不存在 , 则不设置 (返回 nil)
那为了方便 set 下令的使用 , Redis 就出了一些简写 , 比如 : setnx、setex、setpx …
还必要注意的是 , 如果 key 不存在 , 那就会创建出新的键值对 , 如果 key 存在 , 则是让新的 value 覆盖旧的 value , 也有大概修改之前的数据范例 , 原来存在的逾期时间 (ttl) 也会失效
接下来 , 我们就来模拟一下 set 下令的使用
打扫之前的数据 : flushdb / flushall
- 127.0.0.1:6379> set k1 123 # 设置键值对
- OK
- 127.0.0.1:6379> get k1 # 获取键值对
- "123"
- 127.0.0.1:6379> set k2 123 ex 10 # 设置过期时间为 10s
- OK
- 127.0.0.1:6379> ttl k2 # 获取剩余时间
- (integer) 5
- 127.0.0.1:6379> ttl k2 # 键值对如果过期 , 就会返回 -2
- (integer) -2
- 127.0.0.1:6379> get k2 # 此时再去获取 k2 就获取不到了
- (nil)
- 127.0.0.1:6379> set k3 123 nx # nx 指的是不存在才去创建
- OK
- 127.0.0.1:6379> get k3
- "123"
- 127.0.0.1:6379> set k1 456 nx # 此时 k1 已经存在 , nx 再去创建就会失败 , 返回 nil
- (nil)
- 127.0.0.1:6379> get k1 # 得到的还是旧的值
- "123"
- 127.0.0.1:6379> set k4 666 xx # xx 指的是存在才去创建 (覆盖)
- (nil) # 此时 k4 并不存在 , 就会创建失败 , 返回 nil
- 127.0.0.1:6379> get k4
- (nil)
- 127.0.0.1:6379> set k3 789 xx # k3 此时存在 , xx 创建就会成功
- OK
- 127.0.0.1:6379> get k3 # 之前 k3 是 123 , 现在变成 789 , 证明 xx 创建成功
- "789"
复制代码 1.2 get
语法 : get key
我们根据指定的 key 就可以获取到 value 的值
- 127.0.0.1:6379> set k1 123 # 设置键值对
- OK
- 127.0.0.1:6379> get k1 # 获取键值对
- "123"
复制代码 对于 get 来说 , 只支持字符串范例的 value , 如果 value 是其他范例 , 查询就会失败
- 127.0.0.1:6379> lpush k5 11 22 33 # k5 是 list 类型
- (integer) 3
- 127.0.0.1:6379> get k5 # value 是其他类型 , get 就会失败
- (error) WRONGTYPE Operation against a key holding the wrong kind of value
- 127.0.0.1:6379> type k5 # 我们也可以通过 type 查看 k5 的类型
- list
复制代码 1.3 mset、mget
mset 和 mget 可以一次利用多组键值对
一次网络通讯传输就可以举行多组利用
语法 :
mset key1 value1 [key2 value2 …]
mget key1 [key2 …]
- 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 设置多组键值对
- OK
- 127.0.0.1:6379> mget k1 k2 k3 # 获取多组键值对
- 1) "v1"
- 2) "v2"
- 3) "v3"
复制代码 那 mset 和 mget 的时间复杂度为 O(N)
此处的 N 不是整个 Redis 服务器中全部的 key 的数量 , 而是当前下令中给出的 key 的数量 , 那我们也可以变相的以为他的时间复杂度为 O(1)
1.4 setnx、setex、psetex
setnx : 不存在才去设置 , 存在的话就会设置失败
- 127.0.0.1:6379> setnx k1 v1 # setnx 指的是不存在才去设置
- (integer) 1
- 127.0.0.1:6379> get k1 # 获取 k1
- "v1"
- 127.0.0.1:6379> setnx k1 other # 此时 k1 已经存在, setnx 再去设置 k1 就会失败
- (integer) 0
- 127.0.0.1:6379> get k1 # 获取到的还是之前的值
- "v1"
复制代码 setex : 设置超时时间 , 单位为 s
语法 : setex key seconds value
- 127.0.0.1:6379> setex k2 10 v2 # 设置超时时间(单位: s)
- OK
- 127.0.0.1:6379> ttl k2
- (integer) 5
- 127.0.0.1:6379> ttl k2
- (integer) -2
复制代码 psetex : 也是设置超时时间 , 单位是 ms
语法 : psetex key milliseconds value
- 127.0.0.1:6379> psetex k3 100 v3 # 设置超时时间(单位: ms)
- OK
- 127.0.0.1:6379> ttl k3
- (integer) -2
复制代码 1.5 incr、incrby
这一组下令 , 实际上利用的是数字
incr 表现针对 value + 1
incrby 表现针对 value + n
incrbyfloat 表现针对 value +/- 小数
decr 表现针对 value - 1
decrby 表现针对 value - n
我们分别来看
incr 语法 : incr key , 返回值就是 +1 之后的值
要求 key 对应的 value 必须要是整数
- 127.0.0.1:6379> set k1 10 # 设置键值对, 要求 value 为数值
- OK
- 127.0.0.1:6379> incr k1 # 对 k1 进行自增
- (integer) 11 # 返回值代表 +1 之后的数
- 127.0.0.1:6379> get k1
- "11"
- 127.0.0.1:6379> set k2 hello # 设置键值对, 但是 value 设置成字符串类型
- OK
- 127.0.0.1:6379> incr k2 # 对字符串进行自增操作就会失败
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> set k3 1.5 # 对小数进行 incr 操作也会失败
- OK
- 127.0.0.1:6379> incr k3
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> set k4 999999999999999999999999999999999999999999999999999999 # 对一个非常大的数进行自增操作也会失败
- OK
- 127.0.0.1:6379> incr k4
- (error) ERR value is not an integer or out of range
复制代码 那如果我们利用的 key 不存在 , 会怎样处理处罚
- 127.0.0.1:6379> incr k5
- (integer) 1 # 返回值代表 +1 之后的数
- 127.0.0.1:6379> get k5 # 返回值为 1 代表之前的数是 0
- "1"
复制代码 这也就是说 , incr 利用的 key 如果不存在 , 就会把这个 key 的 value 当做 0 来使用
incrby : incrby 可以对 key 举行 +n 的利用
语法 : incrby key increment
- 127.0.0.1:6379> set k6 10 # 设置键值对, 要求 value 为数值
- OK
- 127.0.0.1:6379> incrby k6 100 # 对 k6 进行 +100 的操作
- (integer) 110 # 返回值代表 +n 之后的结果
- 127.0.0.1:6379> get k6
- "110"
- 127.0.0.1:6379> set k7 hello # 设置键值对, 但是 value 设置成字符串类型
- OK
- 127.0.0.1:6379> incrby k7 100 # 对字符串进行 incrby 操作就会失效
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> set k8 3.14 # 设置键值对, 但是 value 设置成浮点数类型
- OK
- 127.0.0.1:6379> incrby k8 100 # 对小数进行 incrby 操作就会失效
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> set k9 99999999999999999999999999999999999999999999999999999999999999 # 对一个非常大的数进行自增操作也会失败
- OK
- 127.0.0.1:6379> incrby k9 100
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> incrby k10 100 # 对一个不存在的 key 进行 incrby 操作, 他会从 0 开始 +n
- (integer) 100
- 127.0.0.1:6379> get k10
- "100"
复制代码 那 incrby 加上一个负数 , 就相称于减法了
但是没人如许用 , 各人都直接使用 decr / decrby 这个下令了
- 127.0.0.1:6379> set k6 10 # 设置键值对, 要求 value 为数值
- OK
- 127.0.0.1:6379> incrby k6 -1 # n 设置成负数就代表减法
- (integer) 109
复制代码 1.6 decr、decrby、incrbyfloat
decr 就是把 key 对应的 value 举行 -1 利用
decr 跟 incr 的要求类似
- key 对应的 value 必须是整数
- 如果这个 key 对应的 value 不存在 , 则当做 0 来处理处罚
- 127.0.0.1:6379> set k1 21 # 设置键值对, 要求 value 为数值
- OK
- 127.0.0.1:6379> decr k1 # -1 操作
- (integer) 20 # 返回值同样是 -1 之后的结果
- 127.0.0.1:6379> set k2 hello # 设置键值对, 但是 value 设置成字符串类型
- OK
- 127.0.0.1:6379> decr k2 # 对字符串进行 incrby 操作就会失效
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> set k3 9999999999999999999999999999999999999999999999999999 # 对一个非常大的数进行自减操作也会失败
- OK
- 127.0.0.1:6379> decr k3
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> set k4 1.5 # 设置键值对, 但是 value 设置成浮点数类型
- OK
- 127.0.0.1:6379> decr k4 # 对小数进行 incrby 操作就会失效
- (error) ERR value is not an integer or out of range
- 127.0.0.1:6379> decr k5 # 对一个不存在的 key 进行 decr 操作, 会把 key 视为 0
- (integer) -1 # 返回值为 -1 就代表 key 原本是 0
- 127.0.0.1:6379> get k5
- "-1"
复制代码 decrby 就是把 key 对应的 value 举行 -n 的利用
- 127.0.0.1:6379> set k1 20 # 设置键值对, 要求 value 为数值
- OK
- 127.0.0.1:6379> decrby k1 10 # 对 k1 进行 -n 操作
- (integer) 10
- 127.0.0.1:6379> get k1
- "10"
- 127.0.0.1:6379> decrby k1 -10 # 如果填写的负数, 那就会认为是 +n 的效果
- (integer) 20
复制代码 incrbyfloat 是针对浮点数举行运算的
- 127.0.0.1:6379> set k1 10.5 # 设置键值对, 要求 value 为浮点数
- OK
- 127.0.0.1:6379> incrbyfloat k1 0.5 # 对 k1 + 0.5
- "11"
- 127.0.0.1:6379> incrbyfloat k1 -0.5 # 对 k1 - 0.5
- "10.5"
复制代码 那 incrbyfloat 是没有对应的 decrbyfloat 如许对应的利用的 , 我们只能将利用数修改成负数来到达减法的结果
上面的这五个利用 , 他们的时间复杂度都是 O(1) 的
别的 , 由于 Redis 处理处罚下令的时间 , 是单线程的模子 , 那多个客户端同时针对同一个 key 举行 incr 利用 , 也就不会引起所谓的 “线程安全” 题目
1.7 append
string 作为字符串 , 他也支持一些常用的利用 , 比如 : 字符串的拼接、获取 / 修改字符串的部分内容、获取字符串的长度
字符串的拼接 : append
获取字符串的部分内容 : getrange
修改字符串的部分内容 : setrange
获取字符串的长度 : strlen
那我们先来看 append , 如果 key 已经存在而且 value 是一个 string 范例 , 那就会将 value 追加到原来的 string 的反面 ; 如果 key 不存在 , 则结果等同于 set 下令 , 也就是直接创建出一个新的键值对对象
语法 : append key value
他的时间复杂度也是 O(1) , 返回值代表追加完成之后 string 的长度
- 127.0.0.1:6379> set k1 hello # 设置键值对
- OK
- 127.0.0.1:6379> append k1 world # 追加字符串
- (integer) 10 # 返回值代表追加完成之后 string 的长度
- 127.0.0.1:6379> get k1 # 我们可以看到, 字符串已经被追加
- "helloworld"
- 127.0.0.1:6379> append k2 hahaha # 如果要追加的 key 不存在, 则是创建出一个新的键值对
- (integer) 6
- 127.0.0.1:6379> get k2
- "hahaha"
复制代码 那如果我们追加一个中文呢 ? 返回值是多少 ?
- 127.0.0.1:6379> append k3 你好
- (integer) 6
复制代码 我们可以看到 , 返回值为 6 , 要注意 : append 返回值的长度的单位是字节
Redis 的字符串不会对字符编码做任那边置处罚 , 也就是说 Redis 不认识字符 , 只认识字节
那为什么会打印 6 呢 ?
这是由于我们使用的 SSH 终端 , 默认的是 UTF8 编码 , 在终端输入汉字之后 , 也就是按照 UTF8 编码的 , 那一个汉字在 UTF8 字符会合 , 通常是 3 个字节的 .
那刚才也说了 , 我们 Redis 不会对字符编码做任那边置处罚 , 那我们看看获取一下 k3 是什么样子的
- 127.0.0.1:6379> get k3
- "\xe4\xbd\xa0\xe5\xa5\xbd"
复制代码 \xe4\xbd\xa0\xe5\xa5\xbd 就是十六进制的 “你好”
我们可以在启动 Redis 客户端的时间 , 加上一个 --raw 如许的选项 , 就可以使 Redis 客户端可以大概自动的把二进制数据实验翻译
那我们就可以重新启动客户端
先按 Ctrl + D 退出 Redis 客户端
不要按到 Ctrl + S , Ctrl + S 是 XShell 的一个特色功能 , 是用来锁定当前屏幕的 , 我们可以通过 Ctrl + Q 取消锁定
然后输入 redis-cli --raw 重新启动客户端
1.8 getrange
getrange 的作用是获取字符串的子串 , 也就是 Java 中的 substring
语法 : getrange key start end , 此中 start 和 end 是左闭右闭的
别的 , Redis 的下标支持负数 , 比如 -1 就代表倒数第一个元素
- 127.0.0.1:6379> set k1 helloworld
- OK
- 127.0.0.1:6379> getrange k1 0 -1 # 第一个元素~最后一个元素
- helloworld
- 127.0.0.1:6379> getrange k1 1 -2 # 第二个元素~倒数第二个元素
- elloworl
复制代码 那我们要是切除中文呢
- 127.0.0.1:6379> getrange k2 0 -1 # 第一个字符~最后一个字符 就相当于获取所有字符, 没啥问题
- 你好
- 127.0.0.1:6379> getrange k2 1 -2 # 但是如果进行切割, 那切除的结果在 utf8 码表上不知道能查出一些什么
- ���
复制代码 1.9 setrange
setrange 的作用就是修改字符串的一部分
语法 : setrange key offset value
此中 , offset 代表偏移量 , 指的是从第几个字符开始举行更换
那什么时间竣事 , 不必要我们思量 , 这是根据 value 的长度自动判定的
返回值就代表更换之后新的字符串的长度
- 127.0.0.1:6379> set k1 helloworld
- OK
- 127.0.0.1:6379> setrange k1 1 aaa # 从 1 开始, 修改成 aaa
- 10 # 返回值就代表替换之后新的字符串的长度
- 127.0.0.1:6379> get k1
- haaaoworld
- 127.0.0.1:6379> setrange k1 1 bbbbbbb # 从 1 号位置开始, 修改成 bbbbbbb
- 10
- 127.0.0.1:6379> get k1
- hbbbbbbbld
- 127.0.0.1:6379> setrange k1 1 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # 如果修改的 value 过长也会影响总长度
- 55
- 127.0.0.1:6379> get k1
- hbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
复制代码 如果当前咱们 value 是一个中笔墨符串 , 举行 setrange 的时间 , 是有大概出现题目的
- 127.0.0.1:6379> set k2 你好世界
- OK
- 127.0.0.1:6379> setrange k2 1 111111
- 12
- 127.0.0.1:6379> get k2
- �111111��界
复制代码 如果我们针对一个不存在的 key 举行更换利用 , 会产生什么样的结果呢 ?
- 127.0.0.1:6379> setrange k4 1 hahaha # 从 1 号位置开始修改不存在的字符串
- 7 # 六个字符返回值为 7?
- 127.0.0.1:6379> get k4
- hahaha
复制代码 那我们的 hahaha 是六个字节 , 但是范围值却变成了 7 , 这是怎么回事 ?
这是由于我们设置的是从第一个元素开始举行 , 那 Redis 的实现的计谋是在前面凭空天生了一个字节 , 这个字节内里的内容就是 0x00 .
1.10 strlen
strlen 的作用就是获取到字符串的长度 , 单位是字节 . 当 key 对应的 value 存储的不是 string 的时间就会报错
- 127.0.0.1:6379> set k1 helloworld
- OK
- 127.0.0.1:6379> strlen k1 # 获取字符个数
- 10
- 127.0.0.1:6379> set k2 你好
- OK
- 127.0.0.1:6379> strlen k2 # 一个汉字三个字节
- 6
- 127.0.0.1:6379> strlen k3 # 获取不存在的 key 就会返回 0
- 0
- 127.0.0.1:6379> lpush k4 111 222 333
- 3
- 127.0.0.1:6379> strlen k4 # 获取其他类型就会报错
- WRONGTYPE Operation against a key holding the wrong kind of value
复制代码 小结
二 . string 的编码方式
字符串的内部编码有三种 :
- int : 生存整数 , 内部是 64 位 / 8 字节 的整数
- embstr : 生存比力短的字符串
- raw : 生存比力长的字符串
我们可以通过 object encoding 下令查察当前数据的编码方式
- 127.0.0.1:6379> set k1 123 # 设置整数类型的字符串
- OK
- 127.0.0.1:6379> object encoding k1 # 查看 value 的编码方式
- "int"
- 127.0.0.1:6379> set k2 hello # 设置字符串类型的字符串(比较短的)
- OK
- 127.0.0.1:6379> object encoding k2 # 查看 value 的编码方式
- "embstr"
- 127.0.0.1:6379> set k3 qwertyuiopasdfghjklzxcvbnmqertyuiopasdfghjklzcvbnm # 设置字符串类型的字符串(比较长的)
- OK
- 127.0.0.1:6379> object encoding k3 # 查看 value 的编码方式
- "raw"
复制代码 那如果我们存入一个小数呢 , 范例是什么 ?
- 127.0.0.1:6379> set k4 3.14 # 存储一个小数
- OK
- 127.0.0.1:6379> object encoding k4
- "embstr" # 我们可以看到编码方式为 embstr
复制代码 Redis 存储小数是使用字符串来存储的 , 这也意味着每次举行算术运算 , 都必要把字符串先转化成小数举行运算 , 然后再将结果转化回字符串
三 . 应用场景
3.1 缓存
3.2 计数器
实际中要开发⼀个成熟、稳固的真实计数体系 , 要面临的寻衅不是这么简朴的 , 我们还必要思量防作弊、按
照差别维度计数、克制单点题目、数据恒久化等等
克制单点题目指的是不能只思量当前主机的数据库 , 也要思量分布式体系中其他主机的数据
3.3 共享会话
我们先看这种情况
如果每个应用服务器都维护本身的会话数据 , 此时各个应用服务器之间数据不共享 , 用户哀求访问到差别的服务器上就大概出现一些不能正确登录的情况了
那更公道的做法就是将会话单独生存到 Redis 中 , 任何服务器要获取用户的登录状态都必要到 Redis 中获取
3.4 手机验证码
一样寻常手机验证码的流程是如许的
- 天生验证码 : 用户输入手机号 , 然后点击获取验证码
但是一样寻常会限定点击获取验证码 , 比如 1min 以内最多获取 5 次验证码 大概 每次获取验证码必须隔断 30s
- 查抄验证码 : 把短信收到的验证码提交到体系中 , 由体系往复验证是否正确
我们可以用伪代码来明确这个题目
- // phoneNumber 相当于用户的手机号
- String 发送验证码 (phoneNumber) {
- key = "shortMsg:limit:" + phoneNumber;
- // 设置过期时间为 1 分钟 (60 秒)
- // 使⽤ NX, 只在不存在 key 时才能设置成功
- boolean r = Redis 执行命令: set key 1 ex 60 nx // 1 代表第一次发送
- // 设置失败 -> 代表用户之前操作过验证码
- if (r == false) {
- // 查看一下目前已经发送的次数
- // incr 返回值是用户发送验证码的次数
- long c = Redis 执⾏命令: incr key // 发送失败代表用户又发了一次验证码, 所以要 +1
- if (c > 5) {
- // 说明超过了⼀分钟 5 次的限制了
- // 限制发送
- return null;
- }
- }
- // 说明要么之前没有设置过⼿机的验证码
- // 要么次数没有超过 5 次
- String validationCode = ⽣成随机的 6 位数的验证码 ();
- validationKey = "validation:" + phoneNumber;// 编写验证码的前缀
- // 验证码 5 分钟 (300 秒) 内有效
- Redis 执⾏命令: set validationKey validationCode ex 300;// 将验证码存入到 Redis 中
- // 返回验证码, 随后通过手机短信发送给⽤⼾
- return validationCode;
- }
- // 验证用户输⼊的验证码是否正确
- // phoneNumber 代表手机号
- // validationCode 代表用户输入的验证码
- boolean 验证验证码 (phoneNumber, validationCode) {
- // 根据手机号构造出 Redis 中存储的 key
- validationKey = "validation:" + phoneNumber;
- // 去 Redis 中查询该电话号是否存在验证码
- String value = Redis 执⾏命令:get validationKey;
- // 验证码不存在
- if (value == null) {
- // 验证失败
- return false;
- }
- // 验证码存在
- // 判断 Redis 中存储的验证码和用户输入的验证码是否相同
- if (value == validationCode) {
- return true;
- } else {
- return false;
- }
- }
复制代码 对于 Redis 中的 string 数据范例 , 已经教学完毕
如果对你有资助的话 , 还请一键三连~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金 |