.NET Core中Redis集群用户数据存取与对象属性查询问题
Redis集群中用户数据存储与查询问题
我想在Redis集群里存储带唯一ID的用户数据(键格式比如User:3737),但现在没法通过代码从集群里获取单个或全部用户数据。不清楚Redis的IDatabase该用哪些方法存取值,同时想知道能不能基于序列化对象的属性在缓存里做查询。我试了两种GetAll方法,但都没得到预期结果:
public async Task Add(TEntity entity, string key) { const string signature = nameof(TEntity); key = $"{signature}:{key}"; var serializedData = JsonConvert.SerializeObject(entity); await _cache.StringSetAsync(key, serializedData); } public async Task<List<Cachable<TEntity>>> GetAll() { const string signature = nameof(TEntity); var data = await _cache.StringGetAsync(signature); var result = JsonConvert.DeserializeObject<List<Cachable<TEntity>>>(data!)!; return result; } public async Task<List<Cachable<TEntity>>> GetAll() { const string signature = nameof(TEntity); var data = await _cache.HashGetAllAsync(signature); var some = JsonConvert.SerializeObject(data); var result = JsonConvert.DeserializeObject<List<Cachable<TEntity>>>(some); return result; }
问题分析与解决方案
1. 单个用户数据的存取
- 存储:你当前的
Add方法是正确的,用StringSetAsync把序列化后的对象存在{实体名}:{唯一ID}格式的键下,完全符合需求。 - 获取单个用户:直接构造目标键,调用
StringGetAsync反序列化即可:
public async Task<Cachable<TEntity>> Get(string key) { const string signature = nameof(TEntity); var fullKey = $"{signature}:{key}"; var data = await _cache.StringGetAsync(fullKey); if (!data.HasValue) return null; return JsonConvert.DeserializeObject<Cachable<TEntity>>(data!)!; }
2. 获取全部用户数据的正确方式
你之前的两种GetAll方法逻辑都错了:
- 第一种去取键名为
User的字符串值,但你实际存储的是User:XXX这类键,根本不存在User这个键,自然拿不到数据。 - 第二种把
User当成哈希表操作,但你存的是独立的字符串键,不是哈希结构,所以返回空。
在Redis集群中,必须用Scan命令批量匹配前缀键(禁止用KEYS,集群下KEYS会遍历所有节点,性能爆炸),然后批量取值:
public async Task<List<Cachable<TEntity>>> GetAll() { const string signature = nameof(TEntity); var prefix = $"{signature}:*"; var allKeys = new List<RedisKey>(); var cursor = 0L; do { var scanResult = await _cache.ScanAsync(cursor, pattern: prefix, pageSize: 100); cursor = scanResult.Cursor; allKeys.AddRange(scanResult.Items); } while (cursor != 0); if (!allKeys.Any()) return new List<Cachable<TEntity>>(); var values = await _cache.StringGetAsync(allKeys.ToArray()); return values.Where(v => v.HasValue) .Select(v => JsonConvert.DeserializeObject<Cachable<TEntity>>(v!)!) .ToList(); }
注意:确认你的StackExchange.Redis版本支持集群下的Scan自动跨节点遍历,部分旧版本可能需要手动处理节点遍历。
3. 基于对象属性的查询方案
Redis本身是键值数据库,不支持直接对序列化对象的属性做SQL式查询。要实现这类需求,有两种可行方案:
- 预建索引键:比如要按用户邮箱查询,额外创建索引键
User:Email:xxx@xx.com,值为对应用户ID3737,查询时先通过索引键拿到ID,再获取用户数据。 - RedisJSON模块:如果你的集群部署了RedisJSON模块,可以把对象以原生JSON格式存储,用JSONPath语法做属性查询,但需要额外部署模块,且客户端要支持对应操作。
内容的提问来源于stack exchange,提问作者Hamed
相关产品推荐
相关产品推荐

