基础数据类型及运用场景

String

常用命令

普通字符串的基本操作:

# 设置 key-value 类型的值
> SET name lin
OK
# 根据 key 获得对应的 value
> GET name
"lin"
# 判断某个 key 是否存在
> EXISTS name
(integer) 1
# 返回 key 所储存的字符串值的长度
> STRLEN name
(integer) 3
# 删除某个 key 对应的值
> DEL name
(integer) 1

批量设置 :

# 批量设置 key-value 类型的值
> MSET key1 value1 key2 value2 
OK
# 批量获取多个 key 对应的 value
> MGET key1 key2 
1) "value1"
2) "value2"

计数器(字符串的内容为整数的时候可以使用):

# 设置 key-value 类型的值
> SET number 0
OK
# 将 key 中储存的数字值增一
> INCR number
(integer) 1
# 将key中存储的数字值加 10
> INCRBY number 10
(integer) 11
# 将 key 中储存的数字值减一
> DECR number
(integer) 10
# 将key中存储的数字值键 10
> DECRBY number 10
(integer) 0

过期(默认为永不过期):

# 设置 key 在 60 秒后过期(该方法是针对已经存在的key设置过期时间)
> EXPIRE name  60 
(integer) 1
# 查看数据还有多久过期
> TTL name 
(integer) 51

#设置 key-value 类型的值,并设置该key的过期时间为 60 秒
> SET key  value EX 60
OK
> SETEX key  60 value
OK

不存在就插入:

# 不存在就插入(not exists)
>SETNX key value
(integer) 1

应用场景

缓存对象

使用 String 来缓存对象有两种方式:

  • 直接缓存整个对象的 JSON,命令例子: SET user:1 '{"name":"xiaolin", "age":18}'
  • 采用将 key 进行分离为 user:ID:属性,采用 MSET 存储,用 MGET 获取各属性值,命令例子: MSET user:1:name xiaolin user:1:age 18 user:2:name xiaomei user:2:age 20

常规计数

阅读量计数:

# 初始化文章的阅读量
> SET aritcle:readcount:1001 0
OK
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 1
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 2
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 3
# 获取对应文章的阅读量
> GET aritcle:readcount:1001
"3"

分布式锁:

SET 命令中有个NX参数 ,当key不存在的时候才插入根据这个功能

  1. nx 如key不存在的话,则插入,可以表示成加锁成功
  2. nx如果key存在的话,则插入失败,可以表示加锁失败
SET lock_key unique_value NX PX 10000
#px 表示过期时间,为了防止死锁

存储用户登录信息:

如果是单一系统,用户信息或者说session则key存储在服务器中,但是如果是分布式系统,用户的登录信息或者其他登录或者更新的其他用户信息,如果只存在A服务器中,B服务器没有共享这些信息,则会出现要求用户再次登录。这时候如何将这些相信息存储在redis中,服务器A 和服务器B 都到redis中获取信息就解决了相关问题。

List

介绍

​ list是简单的字符串列表,根据插入顺序排序,可以从头部和尾部插入数据,列表最大长度是2^32 - 1

内部实现

在但是在 Redis 3.2 版本之后,List 数据类型底层数据结构就只由 quicklist 实现了,替代了双向链表和压缩列表

image-20230927123342858

quicklist(待补充….)

image-20230927123833998

  1. quicklistNode

    typedef struct quicklistNode {
        struct quicklistNode *prev;  //前一个quicklistNode
        struct quicklistNode *next;  //后一个quicklistNode
        unsigned char *zl;           //quicklistNode指向的ziplist
        unsigned int sz;             //ziplist的字节大小
        unsigned int count : 16;     //ziplist中的元素个数
        unsigned int encoding : 2;   //编码格式,原生字节数组或压缩存储
        unsigned int container : 2;  //存储方式
        unsigned int recompress : 1; //数据是否被压缩
        unsigned int attempted_compress : 1; //数据能否被压缩
        unsigned int extra : 10;     //预留的bit位
    } quicklistNode;
    
typedef struct quicklist {
    quicklistNode *head;   // quicklist的链表头
    quicklistNode *tail;   // quicklist的链表尾
    unsigned long count;   // 所有ziplist中的总元素个数
    unsigned long len;     // quicklistNodes的个数
    int fill : QL_FILL_BITS;  // 单独解释
    unsigned int compress : QL_COMP_BITS; // 具体含义是两端各有compress个节点不压缩
    ...
} quicklist;

常用命令

# 将一个或多个值value插入到key列表的表头(最左边),最后的值在最前面
LPUSH key value [value ...] 
# 将一个或多个值value插入到key列表的表尾(最右边)
RPUSH key value [value ...]
# 移除并返回key列表的头元素
LPOP key     
# 移除并返回key列表的尾元素
RPOP key 

# 返回列表key中指定区间内的元素,区间以偏移量start和stop指定,从0开始
LRANGE key start stop

# 从key列表表头弹出一个元素,没有就阻塞timeout秒,如果timeout=0则一直阻塞
BLPOP key [key ...] timeout
# 从key列表表尾弹出一个元素,没有就阻塞timeout秒,如果timeout=0则一直阻塞
BRPOP key [key ...] timeout

应用场景

消息队列

redis中的List是先进先出的,满足使用场景。

image-20230927125319371

  • producer通过LPUSH key value [value…]向List集合中存放消息
  • consumer通过 RPOP key 从集合中获取消息

如何producer没有生成消息,消息集合中也没有数据,而consumer还是一直读取消息,会造成cpu不必要的cpu占用,这时候consumer可以用BRPOP(blocking right pop ),BRPOP命令也称为阻塞式读取,客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据

如何处理重复的消息?

消费者要实现重复消息的判断,需要 2 个方面的要求:

  • 每个消息都有一个全局的 ID。
  • 消费者要记录已经处理过的消息的 ID

因为list不会生成id,所以我们要自行生成id

我们执行以下命令,就把一条全局 ID 为 111000102、库存量为 99 的消息插入了消息队列:

> LPUSH mq "111000102:stock:99"
(integer) 1

List 作为消息队列有什么缺陷?

List 不支持多个消费者消费同一条消息,因为一旦消费者拉取一条消息后,这条消息就从 List 中删除了,无法被其它消费者再次消费。

要实现一条消息可以被多个消费者消费,那么就要将多个消费者组成一个消费组,使得多个消费者可以消费同一条消息,但是 List 类型并不支持消费组的实现

hash

介绍

hash是键值对集合(key-value) eg: value[{fields:,value},….]

string和hash对比,hash更适合用来存储对象

image-20230927130848785

内部实现

Hash类型是通过压缩列表和哈希表实现的在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了

  • 如果哈希类型元素个数小于 512 个(默认值,可由 hash-max-ziplist-entries 配置),所有值小于 64 字节(默认值,可由 hash-max-ziplist-value 配置)的话,Redis 会使用压缩列表作为 Hash 类型的底层数据结构;
  • 如果哈希类型元素不满足上面条件,Redis 会使用哈希表作为 Hash 类型的 底层数据结构。

常用命令

# 存储一个哈希表key的键值
HSET key field value   
# 获取哈希表key对应的field键值
HGET key field

# 在一个哈希表key中存储多个键值对
HMSET key field value [field value...] 
# 批量获取哈希表key中多个field键值
HMGET key field [field ...]       
# 删除哈希表key中的field键值
HDEL key field [field ...]    

# 返回哈希表key中field的数量
HLEN key       
# 返回哈希表key中所有的键值
HGETALL key 

# 为哈希表key中field键的值加上增量n
HINCRBY key field n                         

image-20230927131825394

应用场景

购物车

image-20230927132504164

  • field(商品id)
  • 数量(value)
  • 增加数量(HINCRBY)
  • key(用户id)
  • 购物车数量(hlen)
  • 全选(hgetall)

用户id [{商品id,数量}….,{商品id,数量} ]

set

zset