实用指南:Redis 学习笔记
redis 是按照键值对的方式来存储数据的。
redis 是一个客户端-服务器结构的程序,客户端和服务器之间通过网络来进行通信。
在启动redis客户端的时候,加上一个 --raw 这样的选项,就可以使 redis 客户端尝试把二进制数据进行翻译。
加上 --raw 之前:
加上后:
redis 命令
redis 命令官方文档:Commands | Docs
redis 文档给出的语法格式说明:
[] 相当于一个独立的单元,表示可选项。
| 表示“或者”的意思。
[] 和 [] 之间,是可以同时存在的。
redis 命令不区分大小写
进入redis
redis-cli
存数据
设置一个键值对
set key value
- key 是字符串
- 这个命令后面可以跟很多参数,去看看官方文档
设置多个键值对
mset key value [key value...]
- 时间复杂度O(N),这里的N指的是你输入key、value 的数量
因为 redis 的客户端和服务器之间是靠网络来进行交互的,而网络的传输速度又比较慢,当需要设置多个 key 时,更推荐使用 mset 来进行设置。
当key不存在时,则设置成功,key不存在时,设置失败
setnx key value
设置key的过期时间
单位: 秒
setex key 秒 value
单位:毫秒
psetex key 毫秒 value
拿数据
获取一个value
get key
- 如果当前 key 不存在,则返回 nil
- get命令只能拿字符串类型的value
获取多个value
mget key [key...]
- 时间复杂度O(N),这里的N指的是你输入 key 的数量
因为 redis 的客户端和服务器之间是靠网络来进行交互的,而网络的传输速度又比较慢,当需要获取多个 value 时,更推荐使用 mget 来进行设置。
用来查询当前服务器上匹配的key
keys pattern
- pattern:正则表达式
- keys 命令的时间复杂度是 O(N)
判断 key 是否存在
exists key
- exists 会返回 key 存在的个数
- exist 命令的时间复杂度是 O(1)
删除 数据
del key [key ...]
- del 可以一次性删除多个 key
- del 会返回删除 key 的个数
- del 命令的时间复杂度为O(1)
添加过期时间(秒)
expire key 秒数
时间复杂度 O(1)
返回值:1 表示设置成功;0表示设置失败
添加过期时间 (毫秒)
pexpire key 毫秒数
- 时间复杂度 O(1)
- 返回值:1 表示设置成功;0表示设置失败
查询过期时间(秒)
ttl key
- 时间复杂度 O(1)
- 返回值:剩余的过期时间,-1 表示没有关联过期时间,-2 表示 key 不存在
查询过期时间(毫秒)
pttl key
- 时间复杂度(1)
- 返回值:剩余的过期时间,-1 表示没有关联过期时间,-2 表示 key 不存在
type 查看key所对应的value的类型
type key
redis 中的key的类型为string
redis 中的value的类型可以为 none,list,zset,set,string,hash,stream。
时间复杂度 O(1)

stream:在redis作为消息队列时,使用这个类型的value
查看key所对应value的编码类型
object encoding key

字符串类型

让key所对应的value + 1
incr key
让key所对应的value + n
incrby key 数字
让key所对应的value - 1
decr key
让key所对应的value - n
decrby key 数字
以上命令操作的 value 必须为整数,否则报错。若操作的 value 大于8个字节,则报错。
若以上命令操作的 key 不存在,则就会把这个 key 的 value 当作 0 来使用。
以上命令的返回值都为 value 加/减 操作完成后的值。例如:

让key所对应的 value +/- n
incrbyfloat key 小数
value 必须为数字,否则报错。
若命令操作的 key 不存在,则就会把这个 key 的 value 当作 0 来使用。
返回值为 value 加/减 操作完成后的值
当多个客户端同时针对key进行加减操作时,不会出现“线程安全”问题。因为 redis 采用了单线程模型
让 key 所对应的 value 的后面加上 指定的字符串
append key 字符串
- key 对应的 value 必须为字符串类型。
- 如果 key 不存在,则该命令等价于 set 命令
- 返回值:字符串的长度,单位:字节
截取 字符串
getrange key start end
- key 对应的 value 必须为字符串类型。
- 截取范围是 [start,end],闭区间
- 如果截取汉字,得到的结果很可能不是你想要的
- 范围可以为负数,比如 -1 表示倒数第一个元素,下标为 len - 1 的元素
- 返回值:截取后的字符串
替换 字符串
setrange key offset 字符串
- key 对应的 value 必须为字符串类型。offset 表示替换开始的位置
- 如果截取汉字,得到的结果很可能不是你想要的
- 返回值为替换后的字符串长度
- 当 key 不存在时:

查看字符串长度
strlen key
- key 对应的 value 必须为字符串类型。
- 返回值:字符串长度,单位 字节
hash 类型

向哈希表 key 中设置一个或多个 field-value 对。
hset key field value [field value...]
- 通过 key 可以找到 field 和 value 这个整体
- 通过 field 可以找到 value
- value 只能是字符串类型
- 返回值:设置成功的个数
获取哈希表 key 中指定 field 对应的值。
hget key field
- 返回值:
- 成功:返回
field对应的value。 - 失败(
key或field不存在):返回(nil)。
- 成功:返回
检查哈希表 key 中是否存在指定的 field。
hexists key field
- 返回值:1 表示存在,0 表示不存在
删除哈希表 key 中的一个或多个指定 field。
hdel key field [field...]
- hdel 删除的是 key 对应的 field value 整体,而 del 命令删除的是整个 key
- 返回值:删除成功的个数
查看 key 中的所有 field
hkeys key
- 时间复杂度: O(N),N 为 field 的个数
查看 key 中的所有 field 对应的value
hvals key
- 时间复杂度: O(N),N 为 value的个数
查看 key 中的所有的 field 和所有的value
hgetall key
- 时间复杂度: O(N),N 为 field - value的个数
- 返回值:一个交替排列的 field 和 value 的列表。
- 格式:
[field1, value1, field2, value2, field3, value3, ...]
- 格式:
查看 key 中的一个或多个 field 对应的 value
hmget key field [field...]
- 返回值:一个值的列表,顺序与请求的
field顺序一致。如果某个field不存在,则对应返回nil。
用于增量迭代哈希表中的字段。这是安全遍历大 Hash 的唯一推荐方式。
hscan key cursor [MATCH pattern] [COUNT count]
- 参数:
cursor:游标,从 0 开始。一次调用后返回一个新的游标,下次调用需使用此新游标,直到返回 0 表示迭代结束。MATCH pattern:可选,匹配字段名的模式(通配符风格),例如user:*。COUNT count:可选,建议的每次返回的元素数量(只是一个提示,实际返回可能或多或少),默认值为 10。
- 返回值:一个包含两个元素的数组:
- 下一次迭代要使用的游标(一个整数)。
- 本次迭代返回的 field-value 对列表(也是一个列表,格式和
HGETALL一样是交替的)。
获取哈希表 key 中的字段(field)的数量。
hlen key
时间复杂度:O(1)。Redis 在内部维护了这个计数,所以获取速度极快,与字段多少无关。
返回值:
- 整数:Hash 中的字段数量。
- 0:如果
key不存在。
在 key 对应的 field 不存在时,则设置 hash 中的字段和值
hsetnx key field value
返回值:
1:如果字段是新字段,设置成功。0:如果字段已存在,设置失败。
hash 中的 value 加/减 整数
hincrby key field 整数
- 返回值:执行加法操作后的新值(整数)。
- 特殊说明:
- 如果
key或field不存在,会先将其值初始化为 0,再执行操作。 - 增量
increment可以是负数,实现减法操作。HINCRBY user:1000 score -10(积分扣10)。
- 如果
hash 中的 value 加/减 小数
hincrbyfloat key field 数字
返回值:执行加法操作后的新值(字符串形式的浮点数)。
特殊说明:
- 同
HINCRBY,如果字段不存在,则先初始化为 0.0 再操作。 - 增量
increment可以是负值,也可以是小数(如1.5,-0.7)。
- 同
list 类型

添加元素(头插)
lpush key value [value ...]
lpush 用的是头插法
只能在 key 为 list 结构时使用
返回值:插入后的 list 长度
获取范围内的元素
lrange key start stop
- 获取的范围是 [start,stop] 闭区间
- 只能在 key 为 list 结构时使用
- 返回值:start 到 stop 下标的元素
当 key 存在时,头插元素
lpushx key value [value...]
- 只能在 key 为 list 结构时使用
- 返回值:插入后的 list 长度
- lpush 与 lpushx 的区别:

添加元素(尾插)
rpush key value [value...]
- 只能在 key 为 list 结构时使用
- 返回值:插入后的 list 长度
当 key 存在时,尾插元素
rpushx key value [value...]
- 只能在 key 为 list 结构时使用
- 返回值:插入后的 list 长度
头删 元素
lpop key [count]
- count 表示要头删的元素个数,在 redis 6.2 及以上版本中才能生效
- 时间复杂度:O(N),其中 N 是移除的元素个数。
- 返回值:
- 当
count未指定或为 1 时:返回被删除的元素值。如果列表为空则返回nil。 - 当
count指定且大于 1 时:返回一个包含被删除元素的数组。如果列表为空则返回空数组。
- 当
尾删元素
rpop key [count]
- count 表示要尾删的元素个数,在 redis 6.2 及以上版本中才能生效
- 时间复杂度:O(N),其中 N 是移除的元素个数。
- 返回值:被删除的元素
通过下标查找元素
lindex key index
- 时间复杂度:O(N),N 为列表长度
- 返回值:查找到的元素
在列表中某个基准值(pivot) 的前面或后面插入一个新元素
linsert key <before | after> pivot 元素
- before 表示在基准值元素之后插入;after 表示在基准值元素之前插入。
- 如果列表中有多个与
pivot相等的元素,只以第一个遇到的(从左向右扫描)为基准。 - 时间复杂度:O(N),其中 N 是列表的长度。
- 返回值:
- 成功插入后,返回操作完成后列表的长度。
- 如果基准值
pivot不存在于列表中,返回-1。 - 如果列表
key不存在,将其视为空列表,同样返回-1。
查看列表长度
llen key
时间复杂度:O(1)
返回值:列表长度
连续删除相同元素
lrem key count element
- count 表示要删除元素的个数,element 表示要删除的是谁
- 参数
count的含义和行为: - 时间复杂度:O(N + M),其中 N 是列表的长度,M 是实际被移除的元素个数。
- 返回值:返回实际被移除的元素个数。
移除范围外的所有元素
ltrim key start stop
- 时间复杂度:O(N),其中 N 是列表的长度
- 删除范围为 [start , stop] 之外的所有元素,闭区间
修改指定下标的元素
lset key index element
- index 表示要修改的元素的索引,element 表示要改成的元素
- 时间复杂度:O(N),其中 N 是列表的长度
set 类型

添加元素
sadd key member [member...]
- 返回值:本次操作插入成功的元素个数
查看所有元素
smembers key
- 时间复杂度:O(N)
查看集合中是否存在当前元素
sismember key member
判断 member 是否在当前集合中
返回值:
1: 表示成员是集合的成员(存在)0: 表示成员不是集合的成员(不存在),或者键本身不存在
从 key 中随机删除元素
spop key [count]
key: 集合的键名。count: (可选) 要移除并返回的成员数量。在 Redis 2.6+ 版本中支持。- 返回值:被删除的元素
从 key 中随机获取元素
srandmember key [count]
key: 集合的键名count: (可选) 要获取的成员数量- 返回值:
- 如果未指定
count或count为 1:返回一个随机元素。如果集合为空,则返回nil。 - 如果指定了
count:- 正数 (
count > 0): 返回一个包含count个不重复随机元素的数组。如果count大于集合大小,则返回整个集合。 - 负数 (
count < 0): 返回一个包含abs(count)个元素的数组,允许元素重复(就像有放回的抽样)。如果集合为空,则返回空数组。
- 正数 (
- 如果未指定
移动元素
smove source destination member
- 参数:
source: 源集合的键名。destination: 目标集合的键名。member: 要移动的成员。
- 把 source 中的 member 移动到 destination 中
- 返回值:
1: 表示成员存在且移动成功。0: 表示成员在源集合中不存在,移动操作未执行。
删除元素
srem key member [member...]
- 返回值:删除成功的元素个数
计算并返回给定所有集合键的交集。即返回同时存在于所有指定集合中的成员。
sinter key [key...]
key: 一个或多个集合的键名。必须至少提供一个key。返回值:
包含所有交集成员的列表。
如果指定的任何一个键不存在,则被视为空集合。如果有一个键不存在,那么结果交集就是空集。
如果所有键都不存在,结果也是空集。
时间复杂度:
- O(N * M),最坏情况下的复杂度,其中 N 是最小集合的基数(元素个数),M 是集合的数量。
求交集并存储结果
sinterstore destination key [key...]
参数:
destination: 用于存储交集结果的目标集合的键名。key: 一个或多个用于计算交集的源集合的键名。必须至少提供一个key。
返回值:存储到目标集合中的元素数量
时间复杂度:
- O(N * M),最坏情况下的复杂度,其中 N 是最小集合的基数(元素个数),M 是集合的数量。
集合求并集
sunion key [key...]
key: 一个或多个集合的键名。必须至少提供一个key。- 返回值:求并集之后的结果
- 时间复杂度:O(N),其中 N 是所有给定集合的成员数量总和。
集合求并集并保存
sunionstore destination key [key...]
- 功能:计算给定所有集合键的并集,并将结果保存到
destination指定的集合中。 - 返回值:存储到目标集合中的并集元素的数量。
- 时间复杂度:O(N),其中 N 是所有给定集合的成员数量总和。
求差集
sdiff key [key...]
- 功能:计算并返回第一个集合与其他所有集合的差集。即返回存在于第一个集合中,但不在任何后续集合中的成员
- 返回值:包含差集成员的列表
- 时间复杂度:O(N),其中 N 是所有给定集合的成员数量总和。
求差集并保存
sdiffstore destination key [key...]
- 功能:计算集合的差集,并将结果保存到
destination指定的集合中 - 返回值:存储到目标集合中的差集元素的数量。
- 时间复杂度:O(N),其中 N 是所有给定集合的成员数量总和。
redis 常用数据结构
在redis中使用string等数据类型时,redis对这些类型做了特殊优化,它的内部编码方式可能不是string等数据类型,而是其他类型,但是依然保证承诺有效。

string 类型:
- raw 可以存储较长的字符串,各种类型的字符串
- int 存储数字类型的字符串
- embstr 存储比较短的字符串
hash 类型:
- hashtable:最基本的哈希表
- ziplist:压缩列表,当哈希表中的数据较少时,做的特殊优化,可以节省空间
list 类型:
- linkedlist:基本的链表
- ziplist:压缩列表
从 redis 3.2 版本开始,list 的内部编码使用的是 quicklist(将linkedlist与ziplist的优点相结合)
set 类型:
- hashtable:最基本的哈希表
- intset:存储整数的set
zset 类型:
- skiplist:跳表,每个节点上有多个指针域。从调表上查询元素的时间复杂度为 O(log N)
- ziplist:压缩列表
redis 的应用场景
作为缓存
redis 可以用来作为缓存,存储热点数据。

当服务器接收到查询请求时,请求会先去redis中查找,如果查到了,直接返回响应。如果没查到,则去 mysql 中查询,查询到数据后,将数据写入到 redis 中,之后返回响应。
问题:redis 每次没查到数据,之后会将数据写入 redis 中,那么 redis 使用的内存会不会一直增加?
答:每次将查询到的数据写入 redis 中时,可以给数据添加一个超时时间。其次,redis 也提供了内存淘汰机制。
作为计数器和排行榜
redis 也可以用来作为计数器
场景:文章点赞数、视频播放量、用户积分实时排行榜。
实现:使用
INCR,DECR命令实现原子性计数。使用ZSET(有序集合)可以轻松实现排行榜,能快速进行排名、按分数范围查询等操作。
会话存储
- 场景:在集群环境下存储用户登录会话信息。
- 实现:将Web应用中的Session(用户登录状态、购物车信息等)集中存储在Redis中。
- 优势:相比存储在应用服务器内存中,这样做使得用户请求可以发送到集群中的任何一台服务器,都能获取到登录状态,实现了服务的无状态化,便于水平扩展。
redis 小知识
redis 删除策略
定期删除,每过一段时间,redis会随机抽查一些设置过 过期时间的key,把过期的key删除
惰性删除相结合,当一个key过期时,redis并不会立即删除这个key,而是等到下次用到时,再进行删除操作。
经过上面两个删除策略后,仍然会残留很多过期的key。为了解决这个问题,redis又引入了内存淘汰机制。
redis 是单线程模型,它只用一个线程来处理命令请求。也不是说redis服务器内部真的只有一个线程,其实也有多线程,只不过多线程是用来处理网络IO的。
因为redis是单线程模型,所以当两个自增请求同时到达并且还是操作同一个对象时,redis 不会出现只自增了一次的情况,因为虽然这两个请求都是同时到达的,但是实际上它们是串行执行的(因为只有一个线程在处理请求)。
单线程模型的优点:
不需要加锁解锁,减少了性能开销
不会出现线程安全问题
代码简单易懂,维护起来方便
单线程模型的缺点:
- 当一条命令耗费时间过长时,会阻塞其他命令的执行。
redis为什么就可以使用单线程模型呢?
因为 redis 的核心业务逻辑都是短平快的,不太消耗 cpu,也就不太吃多核了。
redis 是单线程模型,为啥效率还这么高、速度这么快呢?
因为 redis 操作数据都是在内存中完成的,而在内存中处理数据本来就很快。redis的核心功能也比较简单,就是对数据简单的处理一下。redis 的瓶颈不在于 cpu,而在于 网络 IO 的读写速度,redis 采取了 epoll 这样的 IO 多路复用机制。再一个,redis 的数据结构都经过优化,对数据操作的时间复杂度都在 O(1)或 O(logN)之内。还有,单线程模型它不需要加锁解锁等操作,不需要额外消耗 cpu。
IO多路复用:IO多路复用——深入浅出理解select、poll、epoll的实现 - 知乎
简单来说就是一个线程处理多个 socket
redis 不会将存储的数据进行编码转换,这也就意味着出现乱码的概率降低。redis中存储的都是二进制数据。




浙公网安备 33010602011771号