C#高效操作Redis全攻略
一、Redis 简介Redis 是一种开源的、基于内存的数据结构存储系统可用作数据库、缓存和消息代理。它支持多种数据结构包括字符串、哈希、列表、集合、有序集合等具有极高的读写性能在互联网开发中应用广泛。二、环境准备2.1 安装 Redis 服务Windows 环境Redis 官方未提供 Windows 版本安装包可使用第三方维护的版本。下载地址https://github.com/MicrosoftArchive/redis/releases下载后直接安装安装完成后确保 Redis 服务设置为自动启动类型。如需设置密码找到安装目录下的redis.windows-service.conf文件搜索# requirepass foobared在下方添加requirepass 你的密码修改后重启 Redis 服务即可。验证安装打开命令行工具进入 Redis 安装目录输入redis-cli如果设置了密码需要先认证auth 你的密码然后测试基本操作set testkey Hello Redis get testkey能正常返回结果说明安装成功。2.2 安装 C# 客户端库在 C# 项目中操作 Redis推荐使用 StackExchange.Redis这是 .NET 生态中最成熟、性能最好的 Redis 客户端。通过 NuGet 安装Install-Package StackExchange.Redis或使用 .NET CLIdotnet add package StackExchange.Redis三、连接 Redis3.1 单例模式连接推荐ConnectionMultiplexer是线程安全的设计为在整个应用生命周期中复用不应频繁创建和销毁。推荐使用单例模式 异步初始化using StackExchange.Redis; public class RedisConnectionManager { private static LazyConnectionMultiplexer _lazyConnection; private static readonly object _lock new object(); /// summary /// 获取 Redis 连接实例单例 /// /summary public static ConnectionMultiplexer Instance { get { if (_lazyConnection null) { lock (_lock) { if (_lazyConnection null) { _lazyConnection new LazyConnectionMultiplexer(() { var config new ConfigurationOptions { EndPoints { 127.0.0.1:6379 }, Password 你的密码, // 无密码则省略 ConnectTimeout 5000, // 连接超时毫秒 SyncTimeout 5000, // 同步操作超时毫秒 AbortOnConnectFail false, // 连接失败不抛异常后台自动重试 KeepAlive 30, // 保活间隔秒 DefaultDatabase 0 // 默认数据库编号 }; return ConnectionMultiplexer.Connect(config); }); } } } return _lazyConnection.Value; } } /// summary /// 获取数据库实例 /// /summary public static IDatabase GetDatabase(int db -1) { return Instance.GetDatabase(db); } /// summary /// 释放连接 /// /summary public static void Dispose() { if (_lazyConnection ! null _lazyConnection.IsValueCreated) { _lazyConnection.Value.Dispose(); _lazyConnection null; } } }关键参数说明表格参数说明AbortOnConnectFail false保命开关首次连接失败不抛异常后台自动重试ConnectTimeout连接超时时间默认 5000ms跨网络环境可适当调大SyncTimeout同步操作超时上限防止线程长时间阻塞KeepAlive心跳保活间隔防止 NAT 设备或负载均衡器断开空闲连接3.2 在 ASP.NET Core 中集成// Program.cs 或 Startup.cs builder.Services.AddSingletonConnectionMultiplexer(sp { var config new ConfigurationOptions { EndPoints { 127.0.0.1:6379 }, Password 你的密码, AbortOnConnectFail false, ConnectTimeout 5000, SyncTimeout 5000, KeepAlive 30 }; return ConnectionMultiplexer.Connect(config); });使用时通过依赖注入获取public class MyService { private readonly ConnectionMultiplexer _redis; public MyService(ConnectionMultiplexer redis) { _redis redis; } public async Task DoSomethingAsync() { var db _redis.GetDatabase(); await db.StringSetAsync(key, value); } }四、基本数据操作4.1 字符串操作字符串是 Redis 最基础的数据类型可以存储文本、数字或序列化后的对象。var db RedisConnectionManager.GetDatabase(); // 设置值 db.StringSet(username, 张三); // 设置值并指定过期时间 db.StringSet(token, abc123, TimeSpan.FromMinutes(30)); // 获取值 RedisValue value db.StringGet(username); Console.WriteLine(value); // 输出: 张三 // 判断键是否存在 bool exists db.KeyExists(username); // 删除键 db.KeyDelete(username); // 数值递增 db.StringSet(counter, 0); db.StringIncrement(counter); // 变为 1 db.StringIncrement(counter, 5); // 变为 6 // 数值递减 db.StringDecrement(counter, 2); // 变为 4 // 设置键的过期时间 db.KeyExpire(token, TimeSpan.FromHours(1)); // 查看剩余过期时间 TimeSpan? ttl db.KeyTimeToLive(token);重要提醒StringGet返回的是RedisValue类型不是普通的string。判断键是否存在应使用value.IsNull而不是value null或string.IsNullOrEmpty(value)RedisValue result db.StringGet(不存在的键); if (result.IsNull) { Console.WriteLine(键不存在); }4.2 对象序列化存储// 定义实体类 public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } // 存储对象JSON 序列化 var user new User { Id 1001, Name 李四, Age 25 }; string json JsonSerializer.Serialize(user); db.StringSet(user:1001, json, TimeSpan.FromHours(2)); // 读取对象 RedisValue cachedJson db.StringGet(user:1001); if (!cachedJson.IsNull) { var cachedUser JsonSerializer.DeserializeUser(cachedJson); Console.WriteLine($姓名: {cachedUser.Name}, 年龄: {cachedUser.Age}); }4.3 批量操作避免在循环中逐个调用 Redis 命令应使用批量操作减少网络往返// 批量设置 var pairs new KeyValuePairRedisKey, RedisValue[] { new(key1, value1), new(key2, value2), new(key3, value3) }; db.StringSet(pairs); // 批量获取 RedisKey[] keys { key1, key2, key3 }; RedisValue[] values db.StringGet(keys); for (int i 0; i keys.Length; i) { Console.WriteLine(${keys[i]}: {values[i]}); }五、高级数据结构操作5.1 哈希表Hash适合存储对象的多个字段如用户资料、商品信息等。var db RedisConnectionManager.GetDatabase(); // 设置单个字段 db.HashSet(user:1002, name, 王五); db.HashSet(user:1002, age, 24); db.HashSet(user:1002, email, wangwuexample.com); // 批量设置字段 var hashEntries new HashEntry[] { new(name, 赵六), new(age, 30), new(city, 北京) }; db.HashSet(user:1003, hashEntries); // 获取单个字段 RedisValue name db.HashGet(user:1002, name); // 获取所有字段 HashEntry[] allFields db.HashGetAll(user:1002); foreach (var field in allFields) { Console.WriteLine(${field.Name}: {field.Value}); } // 获取指定多个字段 RedisValue[] selectedFields db.HashGet(user:1002, new RedisValue[] { name, email }); // 检查字段是否存在 bool hasField db.HashExists(user:1002, age); // 删除字段 db.HashDelete(user:1002, email); // 数值递增如库存管理 db.HashIncrement(product:1000, stock, -1); // 库存减 15.2 列表List基于链表实现支持从两端快速插入和删除适合消息队列、最新动态等场景。var db RedisConnectionManager.GetDatabase(); // 从左侧插入 db.ListLeftPush(tasks, 任务1); db.ListLeftPush(tasks, 任务2); db.ListLeftPush(tasks, 任务3); // 从右侧插入 db.ListRightPush(tasks, 任务4); // 从左侧弹出 RedisValue task db.ListLeftPop(tasks); // 从右侧弹出 RedisValue lastTask db.ListRightPop(tasks); // 获取指定范围的元素不删除 RedisValue[] items db.ListRange(tasks, 0, -1); // 获取全部 // 获取列表长度 long count db.ListLength(tasks); // 修剪列表保留指定范围 db.ListTrim(tasks, 0, 9); // 只保留前 10 条消息队列示例// 生产者 public void EnqueueOrder(string orderId) { db.ListLeftPush(order_queue, orderId); } // 消费者 public string DequeueOrder() { return db.ListRightPop(order_queue); }5.3 集合Set无序且元素唯一的字符串集合适合标签、去重等场景。var db RedisConnectionManager.GetDatabase(); // 添加元素 db.SetAdd(tags, C#); db.SetAdd(tags, Redis); db.SetAdd(tags, 数据库); // 检查元素是否存在 bool exists db.SetContains(tags, C#); // 获取所有元素 RedisValue[] allTags db.SetMembers(tags); // 获取集合大小 long size db.SetLength(tags); // 移除元素 db.SetRemove(tags, 数据库); // 集合运算 db.SetAdd(set1, a, b, c); db.SetAdd(set2, b, c, d); RedisValue[] union db.SetCombine(SetOperation.Union, set1, set2); // 并集 RedisValue[] intersect db.SetCombine(SetOperation.Intersect, set1, set2); // 交集 RedisValue[] diff db.SetCombine(SetOperation.Difference, set1, set2); // 差集5.4 有序集合Sorted Set每个元素关联一个分数按分数排序适合排行榜、优先级队列等场景。var db RedisConnectionManager.GetDatabase(); // 添加元素带分数 db.SortedSetAdd(leaderboard, new SortedSetEntry[] { new(玩家A, 1000), new(玩家B, 850), new(玩家C, 920), new(玩家D, 780) }); // 增加分数 db.SortedSetIncrement(leaderboard, 玩家B, 50); // 获取排名从低到高 long? rank db.SortedSetRank(leaderboard, 玩家A); // 获取排名从高到低 long? reverseRank db.SortedSetReverseRank(leaderboard, 玩家A); // 获取分数 double? score db.SortedSetScore(leaderboard, 玩家A); // 获取 Top 3 SortedSetEntry[] top3 db.SortedSetRangeByRankWithScores( leaderboard, 0, 2, Order.Descending); foreach (var entry in top3) { Console.WriteLine(${entry.Element}: {entry.Score}); }六、发布与订阅Redis 支持消息发布/订阅模式适合系统间解耦通信。// 获取订阅者 var subscriber RedisConnectionManager.Instance.GetSubscriber(); // 订阅频道 subscriber.Subscribe(chat_channel, (channel, message) { Console.WriteLine($收到消息: {message}); }); // 发布消息 subscriber.Publish(chat_channel, Hello, Redis!); // 取消订阅 subscriber.Unsubscribe(chat_channel);七、事务与管道7.1 事务Redis 事务保证一组命令按顺序执行且不被其他命令打断。var db RedisConnectionManager.GetDatabase(); // 创建事务 ITransaction transaction db.CreateTransaction(); // 添加操作 transaction.StringSetAsync(key1, value1); transaction.StringSetAsync(key2, value2); transaction.StringIncrementAsync(counter); // 执行事务 bool committed await transaction.ExecuteAsync();7.2 管道Batch管道将多个命令打包发送减少网络往返但不保证原子性。var db RedisConnectionManager.GetDatabase(); IBatch batch db.CreateBatch(); // 批量添加操作 await batch.StringSetAsync(batch_key1, value1); await batch.StringSetAsync(batch_key2, value2); await batch.KeyExpireAsync(batch_key1, TimeSpan.FromMinutes(10)); // 执行 batch.Execute();八、最佳实践8.1 连接管理全局单例ConnectionMultiplexer必须全局复用不要在每次请求时创建新实例异步初始化使用LazyConnectionMultiplexer延迟初始化避免启动时阻塞不要缓存 IDatabaseIDatabase是轻量级对象每次通过GetDatabase()获取即可8.2 性能优化批量操作优先使用StringSet(KeyValuePair[])或StringGet(RedisKey[])代替循环单次调用管道减少 RTT复杂混合命令使用IBatch打包合理设置过期时间避免内存无限增长使用异步 API所有方法都有对应的Async版本在异步上下文中务必使用异步方法8.3 异常处理try { var db RedisConnectionManager.GetDatabase(); await db.StringSetAsync(key, value); } catch (RedisConnectionException ex) { // 连接异常处理 Console.WriteLine($Redis 连接失败: {ex.Message}); } catch (RedisTimeoutException ex) { // 超时异常处理 Console.WriteLine($Redis 操作超时: {ex.Message}); } catch (RedisException ex) { // 其他 Redis 异常 Console.WriteLine($Redis 异常: {ex.Message}); }8.4 连接字符串注意事项参数名必须严格小写如password、connectTimeout、abortConnect不要使用 URL 格式如redis://:pwdhost:6379应使用host:port,passwordxxx格式Docker 或云环境必须将localhost替换为真实 IP 或服务名九、完整示例using StackExchange.Redis; using System.Text.Json; class Program { static async Task Main(string[] args) { // 获取数据库实例 var db RedisConnectionManager.GetDatabase(); // 1. 缓存用户信息 var user new { Id 1, Name 测试用户, Email testexample.com }; string userJson JsonSerializer.Serialize(user); await db.StringSetAsync(user:1, userJson, TimeSpan.FromMinutes(30)); // 2. 读取缓存 RedisValue cached await db.StringGetAsync(user:1); if (!cached.IsNull) { var cachedUser JsonSerializer.Deserializeobject(cached); Console.WriteLine($缓存命中: {cachedUser}); } // 3. 计数器 await db.StringSetAsync(page_views, 0); await db.StringIncrementAsync(page_views); Console.WriteLine($页面访问量: {await db.StringGetAsync(page_views)}); // 4. 哈希存储 await db.HashSetAsync(product:100, new HashEntry[] { new(name, 笔记本电脑), new(price, 5999), new(stock, 100) }); // 5. 列表操作 await db.ListLeftPushAsync(recent_orders, ORD001); await db.ListLeftPushAsync(recent_orders, ORD002); RedisValue[] orders await db.ListRangeAsync(recent_orders, 0, -1); Console.WriteLine($最近订单: {string.Join(, , orders)}); } }通过本教程你应该已经掌握了在 C# 中使用 StackExchange.Redis 进行连接、数据操作和性能优化的核心技能。在实际项目中建议根据业务场景合理选择数据结构并始终遵循单例连接、批量操作、异步调用等最佳实践。