参考视频教程:Redis零基础到进阶,最强redis7教程
官网:Redis
参考命令:Redis 中 String(字符串)类型的命令
参考书籍:Redis设计与实现-黄健宏-微信读书
我们都知道 Redis 提供了丰富的数据类型,常见的有五种:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)。
** 二进制安全特点:**
SET和GET命令
:::info
选项
:::
从2.6.12版本开始,redis为SET命令增加了一系列选项:
# 设置 key-value 类型的值
127.0.0.1:6379> set user admin
OK
# 获取一个key
127.0.0.1:6379> get user
"admin"
# 对已存在的值进行设置
127.0.0.1:6379> set user xiaomi
OK
# 会覆盖原来的值
127.0.0.1:6379> get user
"xiaomi"
# 设置一个过期的值 ex: 后面为秒
127.0.0.1:6379> set user aadmin ex 30
OK
# 查看过期时间
127.0.0.1:6379> ttl user
(integer) 25
# 是否存在key
127.0.0.1:6379> EXISTS user
(integer) 0
# 设置一个过期时间 px: 后面为毫秒
127.0.0.1:6379> set user admin px 10000
OK
127.0.0.1:6379> ttl user
(integer) 6
# 设置一个值,当 只有键key不存在的时候才会设置key的值
127.0.0.1:6379> setnx user admin
(integer) 1
127.0.0.1:6379> setnx user xiaomi
(integer) 0
127.0.0.1:6379> get user
"admin"
# 当只有键key存在的时候才会设置key的值
127.0.0.1:6379> set user xioami xx
OK
127.0.0.1:6379> get user
"xioami"
127.0.0.1:6379>
:::warning
Note: 下面这种设计模式并不推荐用来实现redis分布式锁。
:::
批量设置
:::info
Redis MSET 命令设置多个 key 的值为各自对应的 value
:::
# 批量设置对个值 key-value
127.0.0.1:6379> mset user admin age 10 sex 1
OK
# 查看使用key
127.0.0.1:6379> keys *
1) "user"
2) "age"
3) "sex"
# 批量获取key
127.0.0.1:6379> mget age sex
1) "10"
2) "1"
127.0.0.1:6379>
计数器
:::info
# 增加
127.0.0.1:6379> incr age
(integer) 11
# 增量增加
127.0.0.1:6379> incrby age 2
(integer) 13
# 减少
127.0.0.1:6379> decr age
(integer) 12
# 增量减少
127.0.0.1:6379> decrby age 3
(integer) 9
127.0.0.1:6379>
过期时间
:::info
# 设置 key 在 30 秒后过期(该方法是针对已经存在的key设置过期时间)
# expire key seconds [NX|XX|GT|LT]
127.0.0.1:6379> EXPIRE name 30
(integer) 1
# 查看数据还有多久过期
127.0.0.1:6379> TTL name
(integer) 20
# 设置 key-value 类型的值,并设置该 key 的过期时间为 20 秒
# set key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT uni
127.0.0.1:6379> SET name sid10t EX 20
OK
# setex key seconds value
127.0.0.1:6379> SETEX name 20 sid10t
OK
字符串常用方法
:::info
# 获取字符串的长度
127.0.0.1:6379> strlen age
(integer) 1
# 末尾追加值
127.0.0.1:6379> append user xioami
(integer) 11
127.0.0.1:6379> get user
"adminxioami"
# 范围截取
127.0.0.1:6379> getrange user 6 -1
"ioami"
127.0.0.1:6379>
每个sds.h/sdshdr结构表示一个SDS值
struct sdshdr {
//记录buf数组中已使用字节的数量
//等于SDS所保存字符串的长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
};
SDS 和我们认识的 C 字符串不太一样,之所以没有使用 C 语言的字符串表示,因为 SDS 相比于 C 的原生字符串:
C
因为C字符串并不记录自身的长度信息,所以为了获取一个C字符串的长度,程序必须遍历整个字符串,对遇到的每个字符进行计数,直到遇到代表字符串结尾的空字符为止,这个操作的复杂度为O(N)。
**SDS **
计算C字符串长度的过程和C字符串不同,因为SDS在len属性中记录了SDS本身的长度,所以获取一个SDS长度的复杂度仅为O(1)。
C
因为C字符串不记录自身的长度,所以strcat假定用户在执行这个函数时,已经为dest分配了足够多的内存,可以容纳src字符串中的所有内容,而一旦这个假定不成立时,就会产生缓冲区溢出。
举个例子,假设程序里有两个在内存中紧邻着的C字符串s1和s2,其中s1保存了字符串"Redis",而s2则保存了字符串MongoDB
如果一个程序员决定通过执行:将s1的内容修改为"Redis Cluster",但粗心的他却忘了在执行strcat之前为s1分配足够的空间,那么在strcat函数执行之后,s1的数据将溢出到s2所在的空间中,导致s2保存的内容被意外地修改
SDS
SDS的API里面也有一个用于执行拼接操作的sdscat函数,它可以将一个C字符串拼接到给定SDS所保存的字符串的后面,但是在执行拼接操作之前,sdscat会先检查给定SDS的空间是否足够,如果不够的话,sdscat就会先扩展SDS的空间,然后才执行拼接操作。
:::info
字符串对象的编码可以是int、raw或者embstr。
:::
因为 Redis 处理命令是单线程,所以执行命令的过程是原子的。因此 String 数据类型适合计数场景,比如计算访问次数、点赞、转发、库存数量等等。
# 初始化文章的阅读量
127.0.0.1:6379[3]> SET page:10086 0
OK
#阅读量 +1
127.0.0.1:6379[3]> INCR page:10086
(integer) 1
#阅读量 +1
127.0.0.1:6379[3]> INCR page:10086
(integer) 2
# 获取对应文章的阅读量
127.0.0.1:6379[3]> GET page:10086
"2"
SET 命令有个 NX 参数可以实现「key 不存在才插入」,可以用它来实现分布式锁:
一般而言,还会对分布式锁加上过期时间,分布式锁的命令如下:
127.0.0.1:6379[3]> SET lock 10001 NX PX 10000
OK
一些业务场景下我们需要缓存一些信息:比如:用户的登录状态,验证码过期时间等等