Redis基础数据结构及操作命令解析

Redis基础数据结构及操作命令解析


  Redis有五种基础数据结构,分别为string、list、hash、set、zset。

字符串类型(string)

  字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据、JSON化的对象甚至是一张图片。一个字符串类型键允许存储的数据的最大容量是512 MB,String数据结构是简单的key-value类型,value其实不仅是String,也可以是数字。

基础结构

  Redis的字符串是动态字符串,内部结构的实现类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。string在redis内部结构是一个带长度信息的字节数组,叫做"Simple Dynamic String"。

复制代码
struct SDS<T>{
    T capacity; // 数组容量
    T len;  // 数组长度
    byte flags; // 特殊标志位,不用理睬它
    byte[] content; // 数组内容
}

  如上代码所示,capacity表示所分配数组的长度;len表示字符串的实际长度;content表示字符串的内容。
  上面SDS结构使用了泛型T,之所以使用泛型,是因为redis为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示,当字符串比较短的时候,len和capacity就使用byte和short来表示。
  字符串的扩容,字符串长度小于1MB之前,扩容空间采用加倍策略;字符串长度超过1MB之后,为了避免加倍扩容带来的冗余空间的浪费,就每次扩容1MB。

embstr VS raw

  字符串有两种存储方式,在长度特别短时,使用embstr形式存储,长度超过44字节时,使用raw形式存储。
  embstr是将RedisObject对象头结构和SDS对象连续存在一起,一次内存分配即可。
  raw是将RedisObject对象头结构和SDS对象分开存储,内存地址不连续。

复制代码
struct RedisObject{
    int4 type;
    int4 encoding;
    int24 lru;
    int32 refcount;
    void *ptr;
}

  如上代码所示,RedisObject对象头占16字节的内存空间,是每种数据结构共有的结构,且ptr指针指向具体对象内容的内存地址,这里就是SDS的内存地址。

为什么长度超过44字节就会使用raw形式存储呢?

  内存分配器每次分配内存大小分别是2/4/8/16/32/64等字节,一个完整的embstr对象至少需要32个字节的空间(RedisObject对象头16字节+SDS头3字节),字符串总体超过64字节Redis会认为是一个大字符串,选择raw形式存储。
  RedisObject对象头16字节;SDS头3字节;字符串是以null结尾占1字节。总共20字节,所以留给存储数据的空间就只有44字节。

常用命令

  get、set、incr、decr、mget

1. SET(赋值)

  SET key value,对指定key赋值value。

复制代码
SET user:1 zhangsan

2. GET(取值)

  GET key,取得指定key的value值。

复制代码
GET user:1

3. INCR(递增数字)

  INCR key,将key指定为递增数字,每次调用都会自增1。INCR是保证原子性的,即多个线程同时操作不会发生线程不安全的情况。
  注:如果key不为整数时,会报错。

复制代码
INCR num
redis> 1

4. INCRBY(增加指定的整数)

  INCRBY key value,INCRBY与INCR命令类型,只是INCRBY可以对某个key增加指定的整数,而INCR每次都固定增加1。

复制代码
INCRBY num 3
redis> 4

5. DECR(递减数字)

  DECR key,每次调用都会自减1。

复制代码
DECR num
redis> 3

6. DECRBY(减少指定的整数)

  DECRBY key value,每次调用对某个key减少指定的整数。

复制代码
DECRBY num 2
redis> 1

7. INCRBYFLOAT(增加指定浮点数)

  INCRBYFLOAT key value,每次调用对某个key增加指定浮点数。

复制代码
INCRBYFLOAT folat_num 5E+4
redis> 50006.30000000000000071

8. APPEND(尾部追加值)

  APPEND key value,每次调用对某个key增加指定浮点数。如果key不存在,则相当于SET key value,返回追加值的总长度。

复制代码
APPEND user:1 feng
GET user:1
redis> "zhangsanfeng"

9. STRLEN(获取字符串的长度)

  STRLEN key,返回key对应value长度,如果不存在就返回0。

复制代码
STRLEN user:1
redis> (integer) 12

10. MGET(取得多个键值)

  MGET ...key,返回指定的多个key的value值。

复制代码
MGET key1 key2 key3

11. MSET(设置多个键值)

  MSET key value key value,对多个key设置value。

复制代码
MSET key1 k1 key2 k2 key3 k3

列表类型(list)

  Redis的列表相当于Java中的LinkedList(双向链表),亦意味着插入和删除只需O(1),读取需要O(n)。可以巧妙运用列表提供的操作命令来完成队列和栈的数据结构操作。
  列表类型(list)可以用来存储一个有序的字符串列表,常用操作是向列表两端添加元素,或者取得某个片段。列表类型内部是使用双向链表实现的,即向列表两端添加元素的时间复杂度都为O(1),获取越接近两端的元素越快。

常用命令

1. LPUSH(列表左边添加元素)

  LPUSH key value ...value,从列表左边添加指定元素,可以添加多个,返回添加元素后列表的长度。

复制代码
LPUSH numbers 1
redis> 1

2. RPUSH(列表右边添加元素)

  RPUSH key value ...value,从列表右边添加指定元素,可以添加多个,同样返回添加元素之后,当前列表的长度。

复制代码
RPUSH numbers 2
redis> 2

3. LPOP(从列表左边弹出一个元素)

  LPOP key,从列表左边弹出一个元素,该操作分为两步,第一步将元素从列表中移除,第二部将元素返回。

复制代码
LPOP numbers
redis> 1

4. RPOP(从列表右边弹出一个元素)

  RPOP key,从列表右边弹出一个元素,该操作分为两步,第一步将元素从列表中移除,第二部将元素返回。

复制代码
RPOP numbers
redis> 2

5. LLEN(获取列表中元素个数)

  LLEN key,获取列表中元素个数,返回个数。

复制代码
LLEN numbers
redis> 2

6. LRANGE(获取列表片段)

  LRANGE key start stop,获取列表片段,索引从0开始,LRANGE与POP命令不同,LRANGE只取出片段不会将其从列表中删除。

复制代码
LRANGE numbers 0 3
redis>

7. LREM(删除列表中指定值)

  LREM key count value,删除列表中指定值。

  1. 当count > 0时LREM命令会从列表左边开始删除前count个值为value的元素。

  2. 当count < 0时LREM命令会从列表右边开始删除前count个值为value的元素。

  3. 当count = 0时LREM命令会删除所有值为value的元素。

    LREM numbers 0 2

6. LINDEX(获取指定索引位置的元素)

  LINDEX key index,获取指定索引位置的元素,索引从0开始,获取索引为0位置的元素。

复制代码
LINDEX numbers 0

7. LSET(设置指定索引位置的元素)

  LSET key index value,设置指定索引位置的元素,索引从0开始,设置索引为0位置的元素为7。

复制代码
LSET numbers 0 7

8. LTRIM(删除指定范围外的所有元素)

  LTRIM key start end,删除指定范围外的所有元素,删除除0-3位置之外的所有元素。

复制代码
LTRIM numbers 0 3

9. LINSERT(向列表中插入元素)

  LINSERT key AFTER|BEFORE pivot value,向列表中插入元素,在选择在指定元素前面插入还是后面插入。

复制代码
LINSERT numbers AFTER 3 2

  在元素3后插入2。

复制代码
LINSERT numbers BEFORE 3 2

  在元素3前插入2。

集合类型(set)

  Redis的集合相当于Java中的HashSet,内部的键值对是无序且唯一的。内部相当所有元素的value都为null的一个特殊的字典。set可用于需要去重的地方。
  集合类型和列表类型及其相似。但集合类型主要用于求得交集、并集和差集。

常用命令

1. SADD(添加元素)

  SADD key member ...member,添加元素,可以添加多个,当所添加元素已经存在,不再添加。

复制代码
SADD letters a b c d
2. SREM(删除元素)

  SREM key member ...member,删除元素,可以删除多个,返回成功删除个数。

复制代码
SREM letters d

3. SISMEMBER(判断元素是否在集合中)

  SISMEMBER key member,判断元素是否在集合中,有返回1,否则返回0。

复制代码
SISMEMBER letters a

4. SDIFF(差集运算)

  SDIFF key ...key,差集运算。

复制代码
SADD A 1 2 3 4 5
SADD B 2 4 6 8 9
SDIFF A B
1) "1"
2) "3"
3) "5"

  SDIFF A B = A - B,返回即集合A排除掉A与B交集之后的元素。

5. SINTER(交集运算)

  SINTER key ...key,交集运算,返回即集合A与B共有元素。

复制代码
SADD A 1 2 3 4 5
SADD B 2 4 6 8 9
SINTER A B
1) "2"
2) "4"

6. SUNION(并集运算)

  SUNION key ...key,交集运算,返回A + B,所有元素。

复制代码
SADD A 1 2 3 4 5
SADD B 2 4 6 8 9
SUNION A B
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "8"
8) "9"

7. SCARD(获得集合中元素个数)

  SCARD key,获得集合中元素个数。

复制代码
SCARD A

8. SPOP(从集合中弹出一个元素)

  SPOP key,从集合中随机弹出一个元素,因为集合是无序的。

复制代码
SPOP A

散列类型(hash)

  Redis的字典相当于Java语言里面的HashMap,它是无序字典,内部存储了很多键值对。其内部实现结构也和Java的HashMap一样,"数组+链表"形式,如遇hash冲突则用链表串起来。
  大字典的扩容比较耗时,首先需要重新申请新的数组,然后再将旧字典中的所有元素搬移到新数组中。这是一个O(n)级别的操作,单线程的Redis显然承担不起,所以Redis采用渐进式rehash的方式进行扩容。小步搬移,等待所有都搬移完毕之后再释放旧字典的内存。
  一般情况下,当hash元素个数等于数组长度时就会扩容两倍。但是如果当前redis正在bgsave(将数据保存到磁盘),为了减少内存页的过多分离,redis会选择尽量不去扩容,但是如果元素个数已经是数组长度的5倍,那么此时会强制扩容。
  如果hash表中元素个数低于数组长度的10%,redis就会进行缩容,且不考虑bgsave。

hash攻击

  如果hash函数存在偏向性,这种偏向性就会被利用来攻击服务器。因为偏向性强的hash函数会将过多的元素分配到同一个链表中,从而就会使查找从O(1)退化为O(n)。

常用命令

1. HSET(赋值)

  HSET key field value,对key中的field字段设置value。

复制代码
HSET car price 500
HSET car name changan

  以上是分别对car下price字段和name进行赋值,price+name类似于一个对象或一个hashmap。

2. HGET(取值)

  HGET key field,取得指定key下指定的field字段。

复制代码
HGET car price
redis> 500

3. HMSET(批量赋值)

  HMSET key field value field value ...,对指定key下字段批量赋值。

复制代码
HMSET car price 600 name changan

  对car下price字段和name同时进行赋值。

4. HMGET(取值)

  HMGET key field field ...,取得指定key下指定的field字段对应值。

复制代码
HMGET car price name
redis> "600"
redis> "changan"

5. HGETALL(取的所有值)

  HGETALL key,取得指定key下所有字段对应值,返回格式为field-value形式。

复制代码
HGETALL car
redis> "price"
redis> "600"
redis> "name"
redis> "changan"

6. HEXISTS(判断字段是否存在)

  HEXISTS key field,判断指定key下的field字段是否存在,存在返回1,否则返回0。

复制代码
HEXISTS car price
redis> 1

7. HSETNX(当字段不存在时赋值)

  HSETNX key field value,对某个key下field进行赋值,但如果该field存在则不做任何操作,不存在才赋值。

复制代码
HSETNX car price 500
redis> 0
HSETNX car brand changan
redis> 1

8. HINCRBY(增加指定数字)

  HINCRBY key field increment,对指定key的field增加指定数字,类似于字符串类型的INCRBY。

复制代码
HINCRBY car price 400
redis> 1000
HGET car price
redis> "1000"

9. HDEL(删除字段)

  HDEL key field field ...,删除key下field字段,这里可以为多个。

复制代码
HDEL car brand
redis> 1

10. HKEYS(获取所有field字段)

  HKEYS key,获取当前key下所有field字段。

复制代码
HKEYS car
redis> "price"
redis> "name"

11. HVALS(获取所有field字段对应值)

  HVALS key,获取当前key下所有field字段对应值。

复制代码
HVALS car
redis> "1000"
redis> "changan"

12. HLEN(获取field字段数量)

  HLEN key,获取field字段数量。

复制代码
HLEN car
redis> 2

有序集合类型(zset)

  Redis的有序列表首先保证内部value的唯一性,且还可以给每一个value设置一个score代表其排序的权重,zset内部是用跳跃列表来实现的。
  因为zset提供有score进行排序,所有在读取数据时可以指定某一区间的score进行读取数据,从而可以实现一个有序、不重复且可灵活读取的列表。
  有序集合类型和集合类型,一个是无序,一个有序的。有序集合类型与列表类型:

  1. 列表类型是通过链表实现,即两端元素获取速度快,更多用于"日志"或"新鲜事"的应用场景。
  2. 有序集合类型是通过散列表和跳跃表实现,即读取中间数据相比列表类型要快。
  3. 列表类型不能简答的调整某个元素的位置,但有序集合类型可以(通过更改元素的分数)。
  4. 有序集合类型比列表类型更耗费内存。

常用命令

1. ZADD(添加元素)

  ZADD key NX\|XX CH INCR score member score member ...,添加元素,可以添加多个,这里的score可以是应用场景中任何用于排序的元素。

复制代码
ZADD scoreboard 90 Tom 60 Ann 87 Jason

2. ZSCORE(获取分数)

  ZSCORE key member,获取指定key分数。

复制代码
ZSCORE scoreboard Tom

3. ZRANGE(获取某个范围排名的元素:从小到大)

  ZRANGE key start stop WITHSCORES,获取排名在某个范围的元素,WITHSCORES-加上之后会将分数一同返回。

复制代码
ZRANGE scoreboard 0 2
1) "Ann"
2) "Jason"
3) "Tom"

4. ZREVRANGE(获取某个范围排名的元素:从大到小)

  ZREVRANGE key start stop WITHSCORES,获取排名在某个范围的元素,WITHSCORES-加上之后会将分数一同返回。

复制代码
ZREVRANGE scoreboard 0 2
1) "Tom"
2) "Jason"
3) "Ann"

5. ZRANGEBYSCORE(获取指定分数范围的元素)

  ZRANGEBYSCORE key min max WITHSCORES LIMIT offset count,获取指定分数范围的元素,WITHSCORES-加上之后会将分数一同返回。

复制代码
ZRANGEBYSCORE scoreboard 70 100
1) "Jason"
2) "Tom"

6. ZINCRBY(增加指定分数)

  ZINCRBY key score member,对指定key下的元素增加指定分数,如为-10------则表示为减少10分。

复制代码
ZINCRBY scoreboard 20 Ann

7. ZCARD(获取元素个数)

  ZCARD key,获取集合中元素的个数并返回。

复制代码
ZCARD scoreboard
(integer) 3

8. ZCOUNT(统计指定范围的元素个数)

  ZCARD key min max,统计指定范围的元素个数。

复制代码
ZCOUNT scoreboard 60 100
(integer) 3

9. ZREM(删除元素)

  ZREM key member ...member,删除元素。

复制代码
ZREM scoreboard Tom

10. ZRANK(获取元素中排名:从小到大)

  ZREM key member,获取元素在有序集合中排名。

复制代码
ZRANK scoreboard Tom
(integer) 2

11. ZREVRANK(获取元素中排名:从大到小)

  ZREVRANK key member,获取元素在有序集合中排名。

复制代码
ZREVRANK scoreboard Tom
(integer) 0

一键三连,让我的信心像气球一样膨胀!

相关推荐
jeffer_liu38 分钟前
Spring AI 生产级实战:工具调用
java·人工智能·后端·spring·ai编程
Cosolar1 小时前
AutoGen 精通教程:从零到企业级多 Agent 系统架构师
人工智能·后端·面试
狂炫冰美式3 小时前
你还在古法PPT吗,试试HTML呢?免费编辑导出工具给 xdm 放这了
前端·后端·github
万少4 小时前
未来组织的分水岭不是员工数量,而是人才密度
前端·后端·面试
pluviophile_s4 小时前
数据结构:第2讲:线性表
数据结构·笔记
Honmaple4 小时前
终端 AI 编程的两条路:Pi 极简哲学 vs Oh-My-Pi 全能主义深度对决
后端
我是一颗柠檬4 小时前
【Redis】发布订阅与消息队列Day8(2026年)
数据库·redis·后端·缓存
道友可好4 小时前
OpenSpec:轻到起飞的 AI 编程规范层
前端·人工智能·后端
sukioe4 小时前
Redis 持久化+高可用详解:RDB/AOF/混合/主从/哨兵/集群
数据库·redis·缓存