如何将RedisJSON作为关系型数据库合理使用?
一、数据建模:对应关系型表结构
用Redis Key前缀区分不同“表”,比如用户表用user:作为前缀,每个用户的JavaScript对象存储在user:<user_id>的Key下,格式为JSON:
- 示例用户对象:
{ "id": 1001, "username": "john_doe", "email": "john@example.com", "created_at": "2024-05-20T12:00:00Z" }
存储命令:JSON.SET user:1001 $ '{"id":1001,"username":"john_doe","email":"john@example.com","created_at":"2024-05-20T12:00:00Z"}'
二、主键与唯一性约束
- 主键处理:将关系型数据库的主键作为Redis Key的后缀(如
user:1001中的1001),用Redis集合存储已用主键(如user:ids),新增前执行SISMEMBER user:ids 1001检查唯一性,返回1则说明主键已存在。 - 唯一字段约束:用Redis哈希表映射唯一字段到主键,比如用户邮箱的映射表
user:email_map,执行HSET user:email_map john@example.com 1001存储关联关系,新增时用HEXISTS user:email_map new_email@example.com检查字段是否重复。
三、处理关联关系
1. 嵌入式关联(适合小数据量)
直接在主对象中嵌入关联数据数组,比如用户对象中嵌入订单列表:
{ "id": 1001, "username": "john_doe", "orders": [{"order_id": 2001, "total": 99.99}, {"order_id": 2002, "total": 149.99}] }
注意:单个RedisJSON对象有大小限制,关联数据量大时不推荐此方式。
2. 引用式关联(类似外键)
- 关联数据单独存储:订单对象存在
order:<order_id>的Key下,包含外键字段user_id:
{ "id": 2001, "user_id": 1001, "total": 99.99, "order_time": "2024-05-21T09:30:00Z" }
- 用Redis集合存储主数据的关联ID列表:比如
user:1001:orders,执行SADD user:1001:orders 2001 2002存储用户订单ID;查询时先执行SMEMBERS user:1001:orders拿到订单ID,再用JSON.GET order:<order_id>逐个获取详情。
四、模拟SQL查询操作
单条记录查询(对应
SELECT * FROM user WHERE id=1001):JSON.GET user:1001 $条件查询(对应
SELECT username FROM user WHERE email='john@example.com'):
先通过唯一映射表获取主键:HGET user:email_map john@example.com,得到1001后执行JSON.GET user:1001 $.username批量查询(对应
SELECT * FROM user WHERE id IN (1001,1002)):
用批量命令获取多个Key的JSON数据:MGET user:1001 user:1002,自行解析结果即可。更新记录(对应
UPDATE user SET email='new_john@example.com' WHERE id=1001):
执行JSON.SET user:1001 $.email '"new_john@example.com"',同时更新唯一映射表:HSET user:email_map new_john@example.com 1001和HDEL user:email_map john@example.com删除记录(对应
DELETE FROM user WHERE id=1001):
- 删除用户JSON:
DEL user:1001 - 从主键集合移除:
SREM user:ids 1001 - 删除唯一映射:
HDEL user:email_map john@example.com - 删除关联的订单ID集合:
DEL user:1001:orders(若存在)
五、性能优化:索引与批量操作
- 二级索引:对常用查询字段建立Sorted Set索引,比如用户创建时间,执行
ZADD user:created_at 1716187200 1001(1716187200为created_at的时间戳),快速查询时间段内的用户:ZRANGEBYSCORE user:created_at 1716099600 1716187200 - 批量操作:优先使用Redis批量命令(如
MGET、HMSET)减少网络往返,避免循环执行单个操作。
内容的提问来源于stack exchange,提问作者Hypothesis

