在 Redis 中,ZSET
(有序集合)的成员(member)通常是字符串类型,但可以通过 序列化 存储对象。以下是几种常见方法:
方法 1:将对象序列化为 JSON/二进制
步骤:
- 序列化对象(如 JSON、MessagePack、Protobuf 等)。
- 将序列化后的字符串作为
ZSET
的member
,并关联一个分数(score)。
示例(Python):
import redis
import json
# 连接 Redis
r = redis.Redis(host='localhost', port=6379)
# 定义对象
user = {"id": 1, "name": "Alice", "age": 30}
# 序列化为 JSON
user_json = json.dumps(user)
# 存入 ZSET(分数为年龄)
r.zadd("users:by_age", {user_json: user["age"]})
# 查询年龄在 [20,40] 的用户
results = r.zrangebyscore("users:by_age", 20, 40)
for res in results:
print(json.loads(res)) # 反序列化
方法2:使用 Hash + ZSET(推荐)
适用场景
需要频繁修改对象的某些字段时更高效。
步骤:
- 用 Hash 存储完整对象(Key:
obj:id
, Field: Object Data)。 - 用 ZSET 存储对象的 ID + Score,仅用于排序和范围查询。
示例:
# Hash存储对象详情
user_id = "user:1"
r.hset(user_id, mapping={"name": "Alice", "age": "30"})
# ZSET存储ID和分数(年龄)
r.zadd("users:by_age", {user_id: user["age"]})
# 查询时先获取ID列表,再批量从Hash取数据
user_ids = r.zrangebyscore("users:by_age", min=20, max=40)
for id in user_ids:
print(r.hgetall(id)) # {"name": "Alice", ...}
方法3:自定义编码(如 MessagePack/Protobuf)
如果对性能要求高,可以用二进制协议替代 JSON:
import msgpack
# 序列化为 MessagePack
user_bin = msgpack.packb({"id":1, "name":"Bob"})
r.zadd("users:binary", {user_bin: score})
注意事项
更新问题
- ZSET的
member
(如JSON字符串)是不可变的。修改对象需先删除旧值,再插入新值。 - Hash+ZSET方案更适合频繁更新的场景。
- ZSET的
大对象优化
- 避免存储过大的对象到ZSET中,优先用Hash分离数据。
分数重复性
- ZSET的
score
可以重复,但member
必须唯一。若需存重复对象,可在JSON中加入唯一标识符(如UUID)。
- ZSET的
总结
方法 | 优点 | 缺点 |
---|---|---|
直接存JSON | 简单直接 | 更新麻烦 |
Hash+ZSET | 易维护、适合更新 | 需多次查询 |
二进制编码 | 体积小、性能高 | 可读性差 |
根据业务需求选择合适的方式!
内容由零声教学AI助手提供,问题来源于学员提问