You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:22:11