1. 为什么要把对象塞进Redis?

咱们知道Redis是个内存数据库,能存字符串、哈希表这些简单结构。但实际开发中,咱们常常需要保存用户信息、订单数据这些复杂对象。这时候就需要像"打包快递"一样,把对象转成Redis能理解的格式(序列化),取出来时再恢复原样(反序列化)。

举个例子:用户登录后要把用户对象缓存起来,下次直接从Redis读取,而不是每次都查数据库。这时候序列化就派上用场了!


2. 为什么选择StackExchange.Redis?

在C#生态中,StackExchange.Redis是使用最广泛的Redis客户端,它有三大杀手锏:

  • 高性能:支持异步操作和连接池
  • 强类型支持:所有操作都有明确的泛型方法
  • 丰富的数据结构:支持字符串、哈希、列表等所有Redis原生结构

安装方法很简单,NuGet执行:

Install-Package StackExchange.Redis

3. 基础版序列化:JSON大法好

咱们先用最常用的JSON序列化方案。这里选择Newtonsoft.Json(虽然现在有System.Text.Json,但Newtonsoft对复杂类型支持更好)。

示例1:用户对象缓存

using StackExchange.Redis;
using Newtonsoft.Json;

// 用户实体类
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime LastLogin { get; set; }
}

class Program
{
    static void Main()
    {
        // 创建Redis连接(生产环境要用连接池)
        var redis = ConnectionMultiplexer.Connect("localhost");
        var db = redis.GetDatabase();
        
        // 创建测试用户
        var user = new User 
        { 
            Id = 1, 
            Name = "张三", 
            LastLogin = DateTime.Now 
        };
        
        // 序列化操作
        string json = JsonConvert.SerializeObject(user);
        db.StringSet("user:1", json);
        
        // 反序列化操作
        var storedJson = db.StringGet("user:1");
        User cachedUser = JsonConvert.DeserializeObject<User>(storedJson);
        
        Console.WriteLine($"用户名:{cachedUser.Name}"); // 输出:张三
    }
}

这个方案就像用快递箱打包物品:

  1. 把对象装进JSON箱子(序列化)
  2. 把箱子存到Redis仓库
  3. 取出时拆箱恢复物品(反序列化)

4. 进阶版:二进制序列化

当需要更高效的存储时,可以改用二进制格式。这里用MessagePack举例(需要安装MessagePack.CSharp包):

示例2:订单数据存储

using MessagePack;

[MessagePackObject]
public class Order
{
    [Key(0)]
    public int OrderId { get; set; }
    [Key(1)]
    public List<string> Items { get; set; }
    [Key(2)]
    public decimal TotalPrice { get; set; }
}

// 序列化部分
byte[] bytes = MessagePackSerializer.Serialize(order);
db.StringSet("order:1001", bytes);

// 反序列化
var storedBytes = db.StringGet("order:1001").ToString();
Order order = MessagePackSerializer.Deserialize<Order>(storedBytes);

二进制方案就像真空压缩袋:

  • 优点:体积小、速度快
  • 缺点:可读性差、需要提前定义数据结构

5. 什么时候该用什么方案?

应用场景对比

场景 推荐方案 原因
Web API响应缓存 JSON 方便调试,直接查看内容
高频交易数据 二进制 节省内存,提高传输速度
临时会话数据 JSON 结构简单,开发效率高
物联网设备数据 二进制 节省流量,适应低带宽环境

6. 避坑指南:五个必知的注意事项

  1. 循环引用陷阱:对象A引用B,B又引用A会导致序列化失败

    // 解决方案:设置ReferenceLoopHandling
    JsonConvert.SerializeObject(obj, new JsonSerializerSettings {
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });
    
  2. 时区问题:DateTime默认转成UTC时间,建议显式指定时区

    var settings = new JsonSerializerSettings {
        DateTimeZoneHandling = DateTimeZoneHandling.Local
    };
    
  3. 版本兼容:新增字段可能导致反序列化失败

    // 使用[OptionalField]特性标记可选字段
    [OptionalField]
    public string NewField;
    
  4. 性能优化:大对象建议压缩

    using (var ms = new MemoryStream())
    {
        using (var gzip = new GZipStream(ms, CompressionMode.Compress))
        {
            MessagePackSerializer.Serialize(gzip, bigData);
        }
        db.StringSet("bigdata", ms.ToArray());
    }
    
  5. 安全防护:反序列化可能执行构造函数,建议验证数据来源


7. 技术选型对比表

指标 JSON方案 二进制方案
可读性 ★★★★★ ★☆☆☆☆
性能 ★★☆☆☆ ★★★★★
存储空间 ★★☆☆☆ ★★★★★
跨语言支持 ★★★★★ ★★★☆☆
开发便捷性 ★★★★★ ★★★☆☆

8. 总结与扩展

通过StackExchange.Redis+序列化方案,咱们就像给Redis装上了瑞士军刀。但别忘了:

  • 简单场景用JSON,复杂数据用二进制
  • 生产环境务必处理序列化异常
  • 监控Redis内存使用情况

想更深入的话,可以研究这些扩展方向:

  1. 混合序列化:对对象不同部分使用不同格式
  2. Schema演进:使用protobuf的向前兼容特性
  3. 内存优化:尝试Span实现零拷贝序列化

下次当你需要把C#对象放进Redis时,记得先给它们穿上合适的"数据外套"哦!