C# Redis 框架开发技术详解
引言
Redis 是一个高性能的键值存储系统,广泛用于缓存、消息队列和实时分析等场景。在 C# 中,有几个著名的库和框架可以方便地与 Redis 进行交互。以下是几个常用的 C# Redis 库:
-
StackExchange.Redis: 这是目前最流行、最推荐的 C# Redis 客户端,由 StackExchange 团队(也就是开发 Stack Overflow 的团队)开发和维护。
-
ServiceStack.Redis: 这是另一个功能齐全的 Redis 客户端,但需要注意的是,ServiceStack 是一个商业产品,对于非开源项目和商业用途可能需要付费。
-
CSRedis: 这也是一个不错的 Redis 客户端,提供了简单易用的 API。
其中最常用的是 StackExchange.Redis。本篇文章将深入解析 StackExchange.Redis 的概念、原理、作用、应用场景及应用实例。
一、概念与原理
什么是 Redis
Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。Redis 的主要特点是速度快、支持持久化、丰富的数据结构和简单易用的 API。
什么是 StackExchange.Redis
StackExchange.Redis 是一个由 StackExchange 团队开发的 C# 客户端库,用于与 Redis 进行交互。它提供了高效、稳定且功能丰富的 API,适合在 .NET 应用中使用。
StackExchange.Redis 的基本原理
StackExchange.Redis 利用 Redis 的发布/订阅模型和数据结构,通过 TCP 连接与 Redis 服务器进行通信。它内部维护了连接池,以便高效地管理和复用连接,同时提供了丰富的异步操作支持。
二、作用与应用场景
作用
- 缓存:通过缓存热点数据,减少数据库的压力,提高系统性能。
- 消息队列:利用 Redis 的发布/订阅模型和列表结构,实现消息队列功能。
- 分布式锁:利用 Redis 的原子操作和过期时间,实现分布式锁。
- 计数器:利用 Redis 的字符串操作,快速实现计数器功能。
- 会话存储:将用户会话数据存储在 Redis 中,实现分布式会话管理。
- 排行榜:利用 Redis 的有序集合实现高效的排行榜功能。
应用场景
- 电商平台:缓存商品信息、库存数据、用户购物车等。
- 社交网络:缓存用户信息、好友列表、聊天记录等。
- 游戏后台:缓存玩家数据、排行榜、游戏状态等。
- 实时分析:缓存实时统计数据、分析结果等。
- 内容管理系统:缓存文章、评论、标签等。
三、应用实例
下面将通过一个详细的实例,展示如何在 C# 项目中使用 StackExchange.Redis 进行 Redis 操作。
项目准备
安装 StackExchange.Redis
首先,需要在项目中安装 StackExchange.Redis 包。可以使用 NuGet 包管理器进行安装。
使用 NuGet 命令行安装:
Install-Package StackExchange.Redis
或者使用 .NET CLI 安装:
dotnet add package StackExchange.Redis
基本操作实例
连接 Redis
首先,我们需要连接到 Redis 服务器。以下是连接 Redis 的代码示例:
using System;
using StackExchange.Redis;class Program
{private static ConnectionMultiplexer redis;private static IDatabase db;static void Main(string[] args){// 连接到 Redis 服务器redis = ConnectionMultiplexer.Connect("localhost"); // 如果 Redis 运行在本地,使用 "localhost"db = redis.GetDatabase();Console.WriteLine("Connected to Redis");// 关闭连接redis.Close();Console.WriteLine("Redis connection closed.");}
}
在上面的代码中,我们使用 ConnectionMultiplexer.Connect 方法连接到 Redis 服务器,并使用 GetDatabase 方法获取一个 Redis 数据库实例。
字符串操作
下面展示了如何进行字符串类型键值对的操作:
// 设置一个键值对
db.StringSet("mykey", "Hello, Redis!");// 获取键对应的值
string value = db.StringGet("mykey");
Console.WriteLine("mykey: " + value);// 设置一个带过期时间的键
db.StringSet("mykey_expire", "This key will expire in 10 seconds", TimeSpan.FromSeconds(10));// 获取带过期时间的键的值
value = db.StringGet("mykey_expire");
Console.WriteLine("mykey_expire: " + value);// 等待 10 秒后再次尝试获取
System.Threading.Thread.Sleep(10000);
value = db.StringGet("mykey_expire");
Console.WriteLine("mykey_expire after 10 seconds: " + value);
哈希操作
下面展示了如何进行哈希类型数据的操作:
// 设置哈希字段值
db.HashSet("user:1", new HashEntry[]
{new HashEntry("name", "Alice"),new HashEntry("age", 30)
});// 获取哈希字段值
string name = db.HashGet("user:1", "name");
int age = (int)db.HashGet("user:1", "age");
Console.WriteLine($"User: name={name}, age={age}");// 获取所有哈希字段值
HashEntry[] hashEntries = db.HashGetAll("user:1");
foreach (var entry in hashEntries)
{Console.WriteLine($"{entry.Name}: {entry.Value}");
}
列表操作
下面展示了如何进行列表类型数据的操作:
// 添加元素到列表
db.ListRightPush("mylist", "item1");
db.ListRightPush("mylist", "item2");
db.ListRightPush("mylist", "item3");// 获取列表长度
long length = db.ListLength("mylist");
Console.WriteLine($"List length: {length}");// 获取列表中的所有元素
for (long i = 0; i < length; i++)
{string item = db.ListGetByIndex("mylist", i);Console.WriteLine($"List item {i}: {item}");
}// 移除并获取列表中的第一个元素
string firstItem = db.ListLeftPop("mylist");
Console.WriteLine($"First item: {firstItem}");
集合操作
下面展示了如何进行集合类型数据的操作:
// 添加元素到集合
db.SetAdd("myset", "item1");
db.SetAdd("myset", "item2");
db.SetAdd("myset", "item3");// 获取集合中的所有元素
RedisValue[] setItems = db.SetMembers("myset");
foreach (var item in setItems)
{Console.WriteLine($"Set item: {item}");
}// 判断元素是否在集合中
bool isMember = db.SetContains("myset", "item2");
Console.WriteLine($"Is item2 in set: {isMember}");
有序集合操作
下面展示了如何进行有序集合类型数据的操作:
// 添加元素到有序集合
db.SortedSetAdd("myzset", "item1", 1.0);
db.SortedSetAdd("myzset", "item2", 2.0);
db.SortedSetAdd("myzset", "item3", 3.0);// 获取有序集合中的所有元素
SortedSetEntry[] zsetItems = db.SortedSetRangeByRankWithScores("myzset");
foreach (var item in zsetItems)
{Console.WriteLine($"ZSet item: {item.Element}, score: {item.Score}");
}// 获取元素的分数
double score = db.SortedSetScore("myzset", "item2");
Console.WriteLine($"Score of item2: {score}");
高级操作实例
发布/订阅
Redis 的发布/订阅模型非常适合用于消息队列和事件通知。下面是发布/订阅的示例:
using System;
using StackExchange.Redis;class Program
{// 定义 Redis 连接和数据库实例private static ConnectionMultiplexer redis;private static IDatabase db;static void Main(string[] args){// 连接到 Redis 服务器redis = ConnectionMultiplexer.Connect("localhost"); // 这里假设 Redis 运行在本地db = redis.GetDatabase(); // 获取 Redis 数据库实例ISubscriber sub = redis.GetSubscriber(); // 获取 Redis 发布/订阅实例// 订阅频道 "mychannel"sub.Subscribe("mychannel", (channel, message) =>{// 当收到消息时,打印消息内容Console.WriteLine($"Received message: {message}");});// 发布 5 条消息到频道 "mychannel"for (int i = 0; i < 5; i++){sub.Publish("mychannel", $"Hello, Redis! {i}"); // 发布消息// 等待 1 秒再发布下一条消息System.Threading.Thread.Sleep(1000);}// 关闭 Redis 连接redis.Close();}
}
代码详解
定义 Redis 连接和数据库实例:
private static ConnectionMultiplexer redis; private static IDatabase db;
ConnectionMultiplexer redis: 用于管理 Redis 连接。IDatabase db: 用于执行 Redis 数据库操作。连接到 Redis 服务器:
redis = ConnectionMultiplexer.Connect("localhost"); db = redis.GetDatabase(); ISubscriber sub = redis.GetSubscriber();
ConnectionMultiplexer.Connect("localhost"): 连接到本地运行的 Redis 服务器。redis.GetDatabase(): 获取 Redis 数据库实例。redis.GetSubscriber(): 获取 Redis 发布/订阅实例。订阅频道 "mychannel":
sub.Subscribe("mychannel", (channel, message) => {Console.WriteLine($"Received message: {message}"); });
sub.Subscribe("mychannel", ...):订阅频道 "mychannel"。- 当收到消息时,匿名委托
(channel, message) => { ... }会被调用,打印消息内容。发布消息到频道 "mychannel":
for (int i = 0; i < 5; i++) {sub.Publish("mychannel", $"Hello, Redis! {i}");System.Threading.Thread.Sleep(1000); }
- 使用
for循环发布 5 条消息。sub.Publish("mychannel", ...):发布消息到频道 "mychannel"。System.Threading.Thread.Sleep(1000):每次发布后等待 1 秒。关闭 Redis 连接:
redis.Close();
redis.Close():关闭 Redis 连接。
在这个示例中,我们使用 Subscribe 方法订阅了一个频道,并通过 Publish 方法发布消息。
分布式锁
下面展示了如何使用 Redis 实现分布式锁:
using System;
using StackExchange.Redis;public class RedisLock
{// 定义 Redis 数据库实例、锁的键、锁的值及锁的超时时间private readonly IDatabase db;private readonly string lockKey;private readonly string lockValue;private readonly TimeSpan lockTimeout;/// <summary>/// 构造函数,初始化 RedisLock 实例/// </summary>/// <param name="db">Redis 数据库实例</param>/// <param name="lockKey">锁的键</param>/// <param name="lockTimeout">锁的超时时间</param>public RedisLock(IDatabase db, string lockKey, TimeSpan lockTimeout){this.db = db; // 设置 Redis 数据库实例this.lockKey = lockKey; // 设置锁的键this.lockValue = Guid.NewGuid().ToString(); // 生成一个唯一的锁值this.lockTimeout = lockTimeout; // 设置锁的超时时间}/// <summary>/// 尝试获取锁/// </summary>/// <returns>如果成功获取锁,返回 true;否则返回 false</returns>public bool Acquire(){// 尝试设置锁的键和值,并指定超时时间,只有键不存在时才能设置成功return db.StringSet(lockKey, lockValue, lockTimeout, When.NotExists);}/// <summary>/// 释放锁/// </summary>/// <returns>如果成功释放锁,返回 true;否则返回 false</returns>public bool Release(){// 只有当前实例持有的锁值与 Redis 中存储的锁值相同时,才删除锁if (db.StringGet(lockKey) == lockValue){return db.KeyDelete(lockKey); // 删除锁的键}return false;}
}// 使用示例
class Program
{static void Main(string[] args){// 连接到 Redis 服务器var redis = ConnectionMultiplexer.Connect("localhost"); // 这里假设 Redis 运行在本地var db = redis.GetDatabase(); // 获取 Redis 数据库实例// 创建 RedisLock 实例,指定锁的键和超时时间var redisLock = new RedisLock(db, "mylock", TimeSpan.FromSeconds(30));// 尝试获取锁if (redisLock.Acquire()){Console.WriteLine("Lock acquired");// 执行需要锁保护的代码System.Threading.Thread.Sleep(5000); // 模拟需要锁保护的代码执行// 释放锁redisLock.Release();Console.WriteLine("Lock released");}else{Console.WriteLine("Failed to acquire lock");}// 关闭 Redis 连接redis.Close();}
}
在这个示例中,我们使用 StringSet 方法和 When.NotExists 条件来实现分布式锁的获取,使用 KeyDelete 方法来释放锁。
事务操作
Redis 支持事务操作,可以通过 IDatabase.CreateTransaction 方法来创建一个事务,并通过 ITransaction.Execute 方法来执行事务。下面是一个事务操作的示例:
using System;
using StackExchange.Redis;class Program
{static void Main(string[] args){// 连接到 Redis 服务器var redis = ConnectionMultiplexer.Connect("localhost"); // 这里假设 Redis 运行在本地var db = redis.GetDatabase(); // 获取 Redis 数据库实例// 创建一个事务var tran = db.CreateTransaction();// 在事务中设置键值对tran.StringSetAsync("key1", "value1");tran.StringSetAsync("key2", "value2");// 提交事务bool committed = tran.Execute();// 检查事务是否成功提交if (committed){Console.WriteLine("Transaction committed");}else{Console.WriteLine("Transaction failed");}// 关闭 Redis 连接redis.Close();}
}
在这个示例中,我们在事务中设置了两个键值对,并通过 Execute 方法提交事务。
四、结论
通过上面的讲解和示例,我们深入了解了 C# 中使用 StackExchange.Redis 进行 Redis 操作的基本概念、原理、作用、应用场景及具体应用实例。Redis 作为一个高性能的内存数据库,广泛应用于各种场景中,而 StackExchange.Redis 则提供了一个强大且易用的 API,可以帮助我们在 C# 项目中方便地使用 Redis。
通过合理利用 Redis 的强大功能,可以大幅提升系统的性能和稳定性,希望本文能对你在 C# 项目中使用 Redis 提供一些帮助和参考。
相关文章:
C# Redis 框架开发技术详解
引言 Redis 是一个高性能的键值存储系统,广泛用于缓存、消息队列和实时分析等场景。在 C# 中,有几个著名的库和框架可以方便地与 Redis 进行交互。以下是几个常用的 C# Redis 库: StackExchange.Redis: 这是目前最流行、最推荐的 C# Redis 客…...
Rust:Result 和 Error
在 Rust 编程语言中,错误处理是一个核心部分,用于确保程序的健売性和可靠性。Rust 通过 Result 枚举和 Error 特质(trait)来处理错误。 Result 枚举 Result 是一个泛型枚举,用于表示一个操作可能成功或失败。它有两个…...
Python基础(八)——MySql数据库
一.数据库 【库——>表——>数据】 借助数据库对数据进行组织存储,借助SQL语言对数据库、数据进行操作管理 Mysql数据库 下载:https://www.mysql.com/ 查看是否安装配置成功: 安装DBeaver用于Mysql数据库图形化 安装:…...
统一网关--gateway(仅供自己参考)
1、网关的概念: 2、网关的功能: (1):身份认证和权限校验 (2):服务路由(具体的业务路由到具体的服务),负载均衡(多台服务的话ÿ…...
【Leetcode152】分割回文串(回溯 | 递归)
文章目录 一、题目二、思路三、代码 一、题目 二、思路 具体例子和步骤:假设 s "aab",步骤如下: 初始状态: s "aab"path []res [] 第一层递归(外层循环): path []检…...
基于BiGRU+Attention实现风力涡轮机发电量多变量时序预测(PyTorch版)
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对…...
深入探究 Flask 的应用和请求上下文
目标 读完本文后,您应该能够解释: 什么是上下文哪些数据同时存储在应用程序和请求上下文中在 Flask 中处理请求时,处理应用程序和请求上下文所需的步骤如何使用应用程序和请求上下文的代理如何在视图函数中使用current_app和代理request什么…...
C++学习笔记(30)
二十三、随机数 在实际开发中,经常用到随机数,例如:纸牌的游戏洗牌和发牌、生成测试数据等。 函数原型: void srand(unsigned int seed); // 初始化随机数生成器(播种子)。 int rand(); // 获一个取随机数。…...
Rust GUI框架 tauri V2 项目创建
文章目录 Tauri 2.0创建应用文档移动应用开发 Android 前置要求移动应用开发 iOS 前置要求参考资料 Tauri 2.0 Tauri 是一个构建适用于所有主流桌面和移动平台的轻快二进制文件的框架。开发者们可以集成任何用于创建用户界面的可以被编译成 HTML、JavaScript 和 CSS 的前端框架…...
C++继承(上)
1.继承的概念 继承是一个类继承另外一个类,称继承的类为子类/派生类,被继承的类称为父类/基类。 比如下面两个类,Student和Person,Student称为子类,Person称为父类。 #include<iostream> using namespace std…...
在 Vim 中打开文件并快速查询某个字符
在 Vim 中打开文件并快速查询某个字符,可以按照以下步骤操作: 打开 Vim 并加载文件: vim your_file.txt将 your_file.txt 替换为你要查询的文件名。 进入普通模式(如果你还在插入模式或其他模式下): Es…...
oracle 条件取反
在Oracle数据库中,条件取反主要通过逻辑运算符NOT来实现。NOT是一个单目运算符,用于对指定的条件表达式取反。当条件表达式为真(True)时,NOT运算符的结果就是假(False);反之…...
力扣最热一百题——缺失的第一个正数
目录 题目链接:41. 缺失的第一个正数 - 力扣(LeetCode) 题目描述 示例 提示: 解法一:标记数组法 1. 将非正数和超出范围的数替换 2. 使用数组下标标记存在的数字 3. 找到第一个未标记的位置 4. 为什么时间复杂…...
零基础入门AI:一键本地运行各种开源大语言模型 - Ollama
什么是 Ollama? Ollama 是一个可以在本地部署和管理开源大语言模型的框架,由于它极大的简化了开源大语言模型的安装和配置细节,一经推出就广受好评,目前已在github上获得了46k star。 不管是著名的羊驼系列,还是最新…...
3.接口测试的基础/接口关联(Jmeter工具/场景一:我一个人负责所有的接口,项目规模不大)
一、Jmeter接口测试实战 1.场景一:我一个人负责所有的接口:项目规模不大 http:80 https:443 接口文档一般是开发给的,如果没有那就需要抓包。 请求默认值: 2.请求: 请求方式:get,post 请求路径 请求参数 查询字符串参数…...
【matlab】将程序打包为exe文件(matlab r2023a为例)
文章目录 一、安装运行时环境1.1 安装1.2 简介 二、打包三、打包文件为什么很大 一、安装运行时环境 使用 Application Compiler 来将程序打包为exe,相当于你使用C编译器把C语言编译成可执行程序。 在matlab菜单栏–App下面可以看到Application Compiler。 或者在…...
从底层原理上解释clickhouse查询为什么快
ClickHouse 是一个开源的列式数据库管理系统,以其极高的查询性能著称。为了理解 ClickHouse 查询为什么快,我们需要从以下几个方面进行深入探讨,包括其架构设计、存储引擎、索引结构、并行化策略以及内存管理等底层原理。 1. 列式存储&#…...
FEAD:fNIRS-EEG情感数据库(视频刺激)
摘要 本文提出了一种可用于训练情绪识别模型的fNIRS-EEG情感数据库——FEAD。研究共记录了37名被试的脑电活动和脑血流动力学反应,以及被试对24种情绪视听刺激的分类和维度评分。探讨了神经生理信号与主观评分之间的关系,并在前额叶皮层区域发现了显著的…...
标准库标头 <bit>(C++20)学习
<bit>头文件是数值库的一部分。定义用于访问、操作和处理各个位和位序列的函数。例如,有函数可以旋转位、查找连续集或已清除位的数量、查看某个数是否为 2 的整数幂、查找表示数字的最小位数等。 类型 endian (C20) 指示标量类型的端序 (枚举) 函数 bit_ca…...
redis群集三种模式:主从复制、哨兵、集群
redis群集有三种模式 redis群集有三种模式,分别是主从同步/复制、哨兵模式、Cluster,下面会讲解一下三种模式的工作方式,以及如何搭建cluster群集 ●主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
