C# Redis 框架开发技术详解

ops/2024/11/13 9:59:55/

引言

Redis 是一个高性能的键值存储系统,广泛用于缓存、消息队列和实时分析等场景。在 C# 中,有几个著名的库和框架可以方便地与 Redis 进行交互。以下是几个常用的 C# Redis 库:

  1. StackExchange.Redis: 这是目前最流行、最推荐的 C# Redis 客户端,由 StackExchange 团队(也就是开发 Stack Overflow 的团队)开发和维护。

  2. ServiceStack.Redis: 这是另一个功能齐全的 Redis 客户端,但需要注意的是,ServiceStack 是一个商业产品,对于非开源项目和商业用途可能需要付费。

  3. 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 服务器进行通信。它内部维护了连接池,以便高效地管理和复用连接,同时提供了丰富的异步操作支持。

二、作用与应用场景

作用

  1. 缓存:通过缓存热点数据,减少数据库的压力,提高系统性能。
  2. 消息队列:利用 Redis 的发布/订阅模型和列表结构,实现消息队列功能。
  3. 分布式锁:利用 Redis 的原子操作和过期时间,实现分布式锁。
  4. 计数器:利用 Redis 的字符串操作,快速实现计数器功能。
  5. 会话存储:将用户会话数据存储在 Redis 中,实现分布式会话管理。
  6. 排行榜:利用 Redis 的有序集合实现高效的排行榜功能。

应用场景

  1. 电商平台缓存商品信息、库存数据、用户购物车等。
  2. 社交网络缓存用户信息、好友列表、聊天记录等。
  3. 游戏后台缓存玩家数据、排行榜、游戏状态等。
  4. 实时分析缓存实时统计数据、分析结果等。
  5. 内容管理系统缓存文章、评论、标签等。

三、应用实例

下面将通过一个详细的实例,展示如何在 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();}
}

代码详解

  1. 定义 Redis 连接和数据库实例

    private static ConnectionMultiplexer redis;
    private static IDatabase db;
    
    • ConnectionMultiplexer redis: 用于管理 Redis 连接。
    • IDatabase db: 用于执行 Redis 数据库操作。
  2. 连接到 Redis 服务器

    redis = ConnectionMultiplexer.Connect("localhost");
    db = redis.GetDatabase();
    ISubscriber sub = redis.GetSubscriber();
    
    • ConnectionMultiplexer.Connect("localhost"): 连接到本地运行的 Redis 服务器。
    • redis.GetDatabase(): 获取 Redis 数据库实例。
    • redis.GetSubscriber(): 获取 Redis 发布/订阅实例。
  3. 订阅频道 "mychannel"

    sub.Subscribe("mychannel", (channel, message) =>
    {Console.WriteLine($"Received message: {message}");
    });
    
    • sub.Subscribe("mychannel", ...):订阅频道 "mychannel"。
    • 当收到消息时,匿名委托 (channel, message) => { ... } 会被调用,打印消息内容。
  4. 发布消息到频道 "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 秒。
  5. 关闭 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 提供一些帮助和参考。

 


http://www.ppmy.cn/ops/111705.html

相关文章

Flutter-底部选择弹窗(showModalBottomSheet)

前言 现在有个需求&#xff0c;需要用底部弹窗来添加定时的重复。在这里使用原生的showModalBottomSheet来实现 showModalBottomSheet的Props 名称 描述 isScrollControlled全屏还是半屏isDismissible外部是否可以点击&#xff0c;false不可以点击&#xff0c;true可以点击&a…

【STM32】单级与串级PID控制的C语言实现

【STM32】单级与串级PID的C语言实现 前言PID理论什么是PIDPID计算过程PID计算公式Pout、Iout、Dout的作用单级PID与串级PID PID应用单级PID串级PID 前言 笔者最近在学习PID控制器&#xff0c;本文基于Blog做以总结。CSDN上已有大量PID理论知识的优秀文章&#xff0c;因此本文将…

【Kubernetes】(K8S)彻底卸载详细教程

以下全部操作都是使用root用户进行&#xff08;非root用户可以使用sudo&#xff09;&#xff0c;并且全部命令都需要在Kubernetes集群的所有节点分别执行&#xff1a; 第一步、停止K8S 所有节点执行&#xff1a; 1 2 3 systemctl stop kubelet systemctl stop etcd systemct…

[Web安全 网络安全]-XSS跨脚本攻击

文章目录&#xff1a; 一&#xff1a;前言 1.定义 2.漏洞出现的原因 3.鉴别可能存在XSS漏洞的地方 4.攻击原理 5.危害 6.防御 7.环境 7.1 靶场 7.2 自动扫描工具 7.3 手工测试工具 8.payload是什么 二&#xff1a;常用的标签语法 三&#xff1a;XSS的分类 反射…

ubuntu系统服务器离线安装python包

一、根据工程需要本地下载所需python包 1. 下载环境requirements.txt pip freeze > requirements.txt2. 根据requirements.txt下载python包 注意&#xff1a;查看服务器属于x_86架构还是arm架构、cpython还是pypy 2.1 确定服务器架构&#xff08;终端输入&#xff09; …

SpringBoot用kafka.listener监听接受Kafka消息

1.创建kafka监听配置并进行注册 import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.common.serialization.StringDeserializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation…

连续时间,离散频率 傅里叶

时域周期——不是把一个信号周期化&#xff0c;而是周期信号取一个周期是x(t),对其周期化不会发生时域的重叠。故当接收到信号&#xff0c;在DFT时&#xff0c;以整个接收到的时间信号为周期进行延拓 推导公式时思路&#xff1a;时域卷积周期冲击&#xff0c;用傅里叶变换推导出…

react 基础语法

前置知识 类的回顾 通过class关键字定义一个类 类名首字母大写 class类有constructor构造器 new 一个类得到一个实例 类还有方法&#xff0c;该方法也会在其原型上 static静态数据&#xff0c;访问静态属性通过 类名.id getter和setter getter&#xff1a;定义一个属性&…