作为Python开发者,Redis是我们日常开发中绕不开的高性能键值数据库。它的核心优势不仅在于速度,更在于丰富且贴合业务场景的数据结构设计 。本文将从基础用法、Python实操、实战场景、扩展知识点四个维度,全面拆解Redis7的五大核心数据结构(String/Hash/List/Set/ZSet),帮你真正做到学以致用、吃透原理。
文章目录
-
- 一、前置准备:Python操作Redis环境
- 二、核心数据结构详解
-
- (一)String:最基础的键值对,万能通用型
-
- [1. 结构特点](#1. 结构特点)
- [2. 核心命令 & Python实操](#2. 核心命令 & Python实操)
- [3. 实战场景](#3. 实战场景)
- [4. 扩展知识点](#4. 扩展知识点)
- (二)Hash:结构化数据存储,告别JSON序列化
-
- [1. 结构特点](#1. 结构特点)
- [2. 核心命令 & Python实操](#2. 核心命令 & Python实操)
- [3. 实战场景](#3. 实战场景)
- [4. 扩展知识点](#4. 扩展知识点)
- (三)List:有序链表,专为"队列/列表"场景设计
-
- [1. 结构特点](#1. 结构特点)
- [2. 核心命令 & Python实操](#2. 核心命令 & Python实操)
- [3. 实战场景](#3. 实战场景)
- [4. 扩展知识点](#4. 扩展知识点)
- (四)Set:无序去重集合,玩转交集/并集/差集
-
- [1. 结构特点](#1. 结构特点)
- [2. 核心命令 & Python实操](#2. 核心命令 & Python实操)
- [3. 实战场景](#3. 实战场景)
- [4. 扩展知识点](#4. 扩展知识点)
- (五)ZSet:有序集合,专为"排名/排序"场景而生
-
- [1. 结构特点](#1. 结构特点)
- [2. 核心命令 & Python实操](#2. 核心命令 & Python实操)
- [3. 实战场景](#3. 实战场景)
- [4. 扩展知识点](#4. 扩展知识点)
- 三、数据结构选型指南(避坑关键)
- 四、总结
- 拓展学习方向
一、前置准备:Python操作Redis环境
在开始学习前,先搭建Python操作Redis的基础环境,我们使用官方推荐的redis-py库(本文基于最新版redis==5.0.1):
python
# 安装依赖
pip install redis
# 基础连接示例
import redis
# 建立Redis连接(默认本地6379端口,无密码)
r = redis.Redis(
host="127.0.0.1",
port=6379,
db=0, # 选择第0个数据库
decode_responses=True # 自动将返回值从bytes转为字符串,避免手动解码
)
# 测试连接
print(r.ping()) # 输出True则连接成功
二、核心数据结构详解
(一)String:最基础的键值对,万能通用型
1. 结构特点
String是Redis最基础、最核心的数据结构,本质是动态字符串(可扩容),一个Key对应一个Value,Value支持三种类型:
- 纯字符串(如用户名、JSON串);
- 数字(整数/浮点数,支持原子增减);
- 二进制数据(如图片、序列化对象)。
2. 核心命令 & Python实操
| 命令 | 作用 | Python示例 |
|---|---|---|
| set | 单个键值存储 | r.set("name", "zhangsan") |
| mset | 批量存储 | r.mset({"age": 18, "gender": "male"}) |
| get | 单个取值 | print(r.get("name")) # 输出zhangsan |
| mget | 批量取值 | print(r.mget(["age", "gender"])) # ['18','male'] |
| setnx | 不存在才存储(防覆盖) | r.setnx("name", "lisi") # 已存在,返回False |
| setex | 存储+过期时间(秒级) | r.setex("code", 60, "123456") # 60秒后过期 |
| append | 追加字符串 | r.append("name", "_test") # name变为zhangsan_test |
| strlen | 字符串长度 | print(r.strlen("name")) # 输出11 |
| incr/decr | 数字±1(原子操作) | r.incr("age") # age变为19;r.decr("age") # 变回18 |
| incrby/decrby | 数字±指定值 | r.incrby("age", 5) # age变为23 |
| del | 删除键 | r.delete("gender") |
3. 实战场景
- 缓存简单数据:用户昵称、商品详情JSON串(替代数据库查询,提升性能);
- 验证码/Token :利用
setex设置过期时间,自动失效; - 计数场景 :文章阅读量、视频点赞数、库存数量(
incr是原子操作,避免并发问题); - 分布式锁 :基于
setnx实现(不存在则加锁,存在则等待)。
4. 扩展知识点
-
内部编码优化 :Redis会根据Value长度自动选择编码:
- 短数字(≤20位)→
int(整数编码,节省空间); - 短字符串(≤44字节)→
embstr(紧凑存储,减少内存碎片); - 长字符串 →
raw(动态扩容)。
- 短数字(≤20位)→
-
毫秒级过期 :
setex是秒级过期,若需更精细的毫秒级,可用psetex:pythonr.psetex("code", 5000, "654321") # 5000毫秒(5秒)后过期 -
批量操作优势 :
mset/mget相比多次set/get,减少网络IO次数,性能提升10倍以上。
(二)Hash:结构化数据存储,告别JSON序列化
1. 结构特点
Hash是字段-值(field-value)的映射表,一个Key对应多个field-value,相当于"Key嵌套字典"。相比String存储JSON串,Hash的优势是:
- 无需序列化/反序列化,直接操作单个字段;
- 节省内存(避免重复存储Key);
- 局部更新(修改某个字段不影响其他字段)。
2. 核心命令 & Python实操
| 命令 | 作用 | Python示例 |
|---|---|---|
| hset | 单个/批量设置字段 | r.hset("user:1000", "name", "zhangsan") r.hset("user:1000", mapping={"age":23, "gender":"male"}) |
| hget | 单个字段取值 | print(r.hget("user:1000", "name")) # zhangsan |
| hmget | 批量字段取值 | print(r.hmget("user:1000", ["age", "gender"])) # ['23','male'] |
| hgetall | 获取所有字段+值 | print(r.hgetall("user:1000")) # 字典:{'name':'zhangsan',...} |
| hdel | 删除指定字段 | r.hdel("user:1000", "gender") |
| hlen | 统计字段数量 | print(r.hlen("user:1000")) # 输出2(name/age) |
| hincrby | 字段数值原子增减 | r.hincrby("user:1000", "age", 2) # age变为25 |
3. 实战场景
- 用户信息存储:用户ID作为Key,用户名/年龄/手机号作为field,替代数据库单行查询;
- 商品属性存储:商品ID作为Key,价格/库存/分类作为field,支持局部更新(如修改库存);
- 配置中心:单个Key存储一组相关配置,便于批量管理。
4. 扩展知识点
-
大Hash遍历优化 :
hgetall会一次性返回所有字段,若Hash有10万+字段,会阻塞Redis。推荐用hscan分批遍历:python# 分批遍历user:1000的字段,每次取10个 cursor = 0 while True: cursor, data = r.hscan("user:1000", cursor=cursor, count=10) print(data) if cursor == 0: break -
Hash的内存限制:单个Hash最多支持2^32-1个字段,日常业务完全够用。
(三)List:有序链表,专为"队列/列表"场景设计
1. 结构特点
List是双向链表(Redis7优化为压缩列表+快速链表),核心特性:
- 有序(按插入顺序,先进先出);
- 可重复;
- 双端操作(左/右增删)性能极高(O(1));
- 支持阻塞操作(适合消息队列)。
2. 核心命令 & Python实操
| 命令 | 作用 | Python示例 |
|---|---|---|
| lpush/rpush | 左/右添加元素 | r.lpush("mylist", "a", "b", "c") # 列表:c b a r.rpush("mylist", "1", "2", "3") # 列表:c b a 1 2 3 |
| lrange | 按索引查看元素(0开始,-1结束) | print(r.lrange("mylist", 0, -1)) # 输出所有元素 |
| lpop/rpop | 左/右删除并返回元素 | print(r.lpop("mylist")) # 输出c print(r.rpop("mylist")) # 输出3 |
| llen | 列表长度 | print(r.llen("mylist")) # 输出4(b a 1 2) |
| blpop/brpop | 阻塞式删除(无元素则等待) | print(r.blpop("mylist", timeout=0)) # 无限等待,直到有元素 |
3. 实战场景
- 消息队列 :基于
lpush+brpop实现简单的生产者-消费者模型(生产者lpush发消息,消费者brpop阻塞取消息); - 评论列表:文章ID作为Key,评论内容按时间rpush添加,lrange分页展示;
- 排队系统:如秒杀排队、客服排队,lpush入队,lpop出队。
4. 扩展知识点
-
列表裁剪 :
ltrim保留指定范围元素,适合限制列表长度(如只保留最新100条评论):pythonr.ltrim("comment:1001", 0, 99) # 只保留前100条评论 -
Redis消息队列局限性:相比RabbitMQ/Kafka,Redis List做消息队列无持久化保障(需开启AOF/RDB)、无重试机制、无死信队列,适合轻量级场景;
-
BRPOPLPUSH:原子性将一个列表的尾部元素移到另一个列表头部,适合"可靠消息队列"(避免消费者宕机丢失消息)。
(四)Set:无序去重集合,玩转交集/并集/差集
1. 结构特点
Set是无序、唯一的字符串集合,底层基于哈希表实现,核心优势:
- 自动去重(重复添加的元素会被忽略);
- 快速判断元素是否存在(O(1));
- 支持集合运算(交集、并集、差集)。
2. 核心命令 & Python实操
| 命令 | 作用 | Python示例 |
|---|---|---|
| sadd | 添加元素(自动去重) | r.sadd("myset", "a", "b", "c", "a") # 实际只添加a/b/c |
| smembers | 查看所有元素 | print(r.smembers("myset")) # {'a','b','c'} |
| sismember | 判断元素是否存在 | print(r.sismember("myset", "a")) # True |
| srem | 删除元素 | r.srem("myset", "a") |
| scard | 统计元素个数 | print(r.scard("myset")) # 2(b/c) |
| sinter | 交集(多个集合共同元素) | r.sadd("set1", "a","b","c"); r.sadd("set2","c","d","e") print(r.sinter("set1", "set2")) # {'c'} |
| sunion | 并集(合并去重) | print(r.sunion("set1", "set2")) # {'a','b','c','d','e'} |
| sdiff | 差集(A有B没有) | print(r.sdiff("set1", "set2")) # {'a','b'} |
3. 实战场景
-
好友关系 :用户A的关注列表存为Set,通过
sinter计算共同好友; -
标签系统:文章标签去重、用户兴趣标签存储;
-
抽奖系统 :
srandmember随机取N个元素(不删除),spop随机抽奖(删除):pythonr.sadd("lottery", "user1", "user2", "user3", "user4") print(r.srandmember("lottery", 2)) # 随机抽2人,不删除 print(r.spop("lottery")) # 随机抽1人,从集合中删除
4. 扩展知识点
- 集合运算性能:Redis的集合运算基于哈希表,百万级元素的交集运算也能毫秒级完成;
- SSCAN遍历 :和Hash的hscan同理,避免
smembers阻塞Redis,适合大Set遍历。
(五)ZSet:有序集合,专为"排名/排序"场景而生
1. 结构特点
ZSet(Sorted Set)是Set的增强版:有序、唯一、带分数(score),底层基于"跳跃表+哈希表"实现,核心特性:
- 元素唯一(同Set);
- 按score排序(score可重复,元素不可重复);
- 支持按排名/分数范围查询;
- 支持score原子增减。
2. 核心命令 & Python实操
| 命令 | 作用 | Python示例 |
|---|---|---|
| zadd | 添加元素(score+值) | r.zadd("rank", {"zhangsan":90, "lisi":80, "wangwu":70}) |
| zrange | 正序查看(score从低到高) | print(r.zrange("rank", 0, -1)) # ['wangwu','lisi','zhangsan'] |
| zrevrange | 倒序查看(score从高到低) | print(r.zrevrange("rank", 0, -1)) # ['zhangsan','lisi','wangwu'] |
| zscore | 查看元素score | print(r.zscore("rank", "zhangsan")) # 90.0 |
| zincrby | score原子增减 | r.zincrby("rank", 5, "zhangsan") # zhangsan的score变为95 |
| zrevrank | 查看排名(从高到低,0开始) | print(r.zrevrank("rank", "zhangsan")) # 0(第1名) |
| zcard | 统计元素数量 | print(r.zcard("rank")) # 3 |
| zrangebyscore | 按score范围查询 | print(r.zrangebyscore("rank", 75, 90)) # ['lisi'] |
3. 实战场景
-
排行榜 :游戏战力榜、文章阅读榜、电商销量榜(
zrevrange取前N名); -
积分系统 :用户积分存储,
zincrby增减积分,zrevrank查排名; -
延时队列 :将任务执行时间作为score,定时扫描score≤当前时间的元素执行:
pythonimport time # 添加延时任务(10秒后执行) delay_time = int(time.time()) + 10 r.zadd("delay_queue", {"task1": delay_time}) # 消费延时任务 while True: current_time = int(time.time()) # 取score≤当前时间的第一个任务 tasks = r.zrangebyscore("delay_queue", 0, current_time, start=0, num=1) if not tasks: time.sleep(1) continue task = tasks[0] # 执行任务(此处简化为打印) print(f"执行任务:{task}") # 删除已执行任务 r.zrem("delay_queue", task)
4. 扩展知识点
-
跳跃表原理:ZSet的排序依赖跳跃表,相比红黑树,跳跃表的插入/删除/查询性能更稳定,且实现更简单;
-
分数精度:score支持64位浮点数,若需整数排序,建议用整数作为score(避免浮点精度问题);
-
批量删除 :
zremrangebyrank按排名删除,zremrangebyscore按分数范围删除:pythonr.zremrangebyrank("rank", 0, 1) # 删除排名最后2名 r.zremrangebyscore("rank", 0, 80) # 删除score≤80的元素
三、数据结构选型指南(避坑关键)
| 业务场景 | 推荐数据结构 | 避坑点 |
|---|---|---|
| 简单键值缓存、计数、验证码 | String | 避免存储超大字符串(建议≤10KB) |
| 用户/商品等结构化数据 | Hash | 避免单个Hash字段数过万(影响遍历性能) |
| 消息队列、评论列表、排队 | List | 避免用lindex查询中间元素(O(n)性能差) |
| 去重、好友交集、标签 | Set | 无需排序时优先用Set,而非ZSet(节省内存) |
| 排行榜、积分、延时队列 | ZSet | score尽量用整数,避免浮点精度问题 |
四、总结
Redis的核心价值在于"用对数据结构解决对应业务问题":
- String是万能基础,但不要滥用(比如结构化数据优先用Hash);
- Hash适合结构化存储,减少序列化开销;
- List是轻量级消息队列的首选,阻塞操作是核心;
- Set的去重和集合运算,完美适配社交/标签场景;
- ZSet的有序特性,是排行榜类场景的最优解。
学习Redis数据结构的关键,不仅是记住命令,更要理解每个结构的底层设计和适用场景。结合Python实操,把这些知识点落地到具体业务中(比如用String做计数、用ZSet做排行榜),才能真正吃透Redis的核心能力。
拓展学习方向
- Redis持久化(RDB/AOF):保证数据不丢失;
- Redis集群(主从/哨兵/集群):解决高可用和扩容问题;
- Redis高级特性(布隆过滤器、位图、HyperLogLog):解决海量数据统计问题。