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}"); // 输出:张三
}
}
这个方案就像用快递箱打包物品:
- 把对象装进JSON箱子(序列化)
- 把箱子存到Redis仓库
- 取出时拆箱恢复物品(反序列化)
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. 避坑指南:五个必知的注意事项
循环引用陷阱:对象A引用B,B又引用A会导致序列化失败
// 解决方案:设置ReferenceLoopHandling JsonConvert.SerializeObject(obj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
时区问题:DateTime默认转成UTC时间,建议显式指定时区
var settings = new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Local };
版本兼容:新增字段可能导致反序列化失败
// 使用[OptionalField]特性标记可选字段 [OptionalField] public string NewField;
性能优化:大对象建议压缩
using (var ms = new MemoryStream()) { using (var gzip = new GZipStream(ms, CompressionMode.Compress)) { MessagePackSerializer.Serialize(gzip, bigData); } db.StringSet("bigdata", ms.ToArray()); }
安全防护:反序列化可能执行构造函数,建议验证数据来源
7. 技术选型对比表
指标 | JSON方案 | 二进制方案 |
---|---|---|
可读性 | ★★★★★ | ★☆☆☆☆ |
性能 | ★★☆☆☆ | ★★★★★ |
存储空间 | ★★☆☆☆ | ★★★★★ |
跨语言支持 | ★★★★★ | ★★★☆☆ |
开发便捷性 | ★★★★★ | ★★★☆☆ |
8. 总结与扩展
通过StackExchange.Redis+序列化方案,咱们就像给Redis装上了瑞士军刀。但别忘了:
- 简单场景用JSON,复杂数据用二进制
- 生产环境务必处理序列化异常
- 监控Redis内存使用情况
想更深入的话,可以研究这些扩展方向:
- 混合序列化:对对象不同部分使用不同格式
- Schema演进:使用protobuf的向前兼容特性
- 内存优化:尝试Span
实现零拷贝序列化
下次当你需要把C#对象放进Redis时,记得先给它们穿上合适的"数据外套"哦!