1.添加包:StackExchange.Redis

2.在配置文件里面,新建Redis的有关配置信息

Name是别名,可以任意起。Ip是Redis的服务端地址,例如安装本地,就是127.0.0.1,端口号Port默认是6379,密码可以通过Redis安装的根目录下的配置文件进行设置,Timeout是连接的超时时间,Db是使用Redis的DB区,一般Redis的DB区默认是0到15。注意:此处的配置使用的是数组,用于将来进行Redis分布式操作的可拓展。

注:我是本地部署的Redis,所以在本地有服务端和客户端,在初始情况下,Redis还没有密码,需要我们自己去设置,找到Redis的安装文件

进入图中的.conf文件去编辑

把#requirepass的#注释去掉 然后重新设置密码,设置完成后保存

cmd运行该文件夹,启动服务端并且指定配置文件

然后开启服务端,就可以进行本地redis开发调试了

3.Ysq.Core.Entity,然后新建一个实体类,叫RedisConfig,用于读取到配置文件的Redis信息进行赋值使用

4.在Common工具文件夹下,新建 Ysq.Core.Redis类库项目,并新建 RedisManage 类和对应接口 IRedisManage,如下图。然后,在该项目里面,引用共用包项目Ysq.Core.Package,用以使用Redis有关功能。

点击查看代码
public interface IRedisManage
{
/// <summary>
/// 设置一个 键值对
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="ts"></param>
void SetValue(string key, object value, TimeSpan ts);
/// <summary>
/// //获取 Reids 缓存值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
string GetValue(string key);
/// <summary>
/// 获取序列化值
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
TEntity Get<TEntity>(string key);
/// <summary>
/// 判断Key是否存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
bool Get(string key);
/// <summary>
/// 移除某个Key和值
/// </summary>
/// <param name="key"></param>
void Remove(string key);
/// <summary>
/// 清空Redis
/// </summary>
void Clear();
/// <summary>
/// 异步获取 Reids 缓存值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task<string> GetValueAsync(string key);
/// <summary>
/// 异步获取序列化值
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<TEntity> GetAsync<TEntity>(string key);
Task SetAsync(string key, object value, TimeSpan cacheTime);
Task<bool> GetAsync(string key);
/// <summary>
/// 异步移除指定的key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task RemoveAsync(string key);
/// <summary>
/// 异步移除模糊查询到的key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task RemoveByKey(string key);
/// <summary>
/// 异步全部清空
/// </summary>
/// <returns></returns>
Task ClearAsync();
}
点击查看代码
public class RedisManage : IRedisManage
{
public volatile ConnectionMultiplexer _redisConnection;
private readonly object _redisConnectionLock = new object();
private readonly ConfigurationOptions _configOptions;
private readonly ILogger<RedisManage> _logger; public RedisManage(ILogger<RedisManage> logger)
{
_logger = logger;
ConfigurationOptions options = ReadRedisSetting();
if (options == null)
{
_logger.LogError("Redis数据库配置有误");
}
this._configOptions = options;
this._redisConnection = ConnectionRedis();
} private ConfigurationOptions ReadRedisSetting()
{
try
{
List<RedisConfigInfo> config = AppHelper.Instance.ReadAppSettings<RedisConfigInfo>(new string[] { "Redis" }); // 读取Redis配置信息
if (config.Any())
{
ConfigurationOptions options = new ConfigurationOptions
{
EndPoints =
{
{
config.FirstOrDefault().Ip,
config.FirstOrDefault().Port
}
},
ClientName = config.FirstOrDefault().Name,
Password = config.FirstOrDefault().Password,
ConnectTimeout = config.FirstOrDefault().Timeout,
DefaultDatabase = config.FirstOrDefault().Db,
};
return options;
}
return null;
}
catch (Exception ex)
{
_logger.LogError($"获取Redis配置信息失败:{ex.Message}");
return null;
} } private ConnectionMultiplexer ConnectionRedis()
{
if (this._redisConnection != null && this._redisConnection.IsConnected)
{
return this._redisConnection; // 已有连接,直接使用
}
lock (_redisConnectionLock)
{
if (this._redisConnection != null)
{
this._redisConnection.Dispose(); // 释放,重连
}
try
{
this._redisConnection = ConnectionMultiplexer.Connect(_configOptions);
}
catch (Exception ex)
{
_logger.LogError($"Redis服务启动失败:{ex.Message}");
}
}
return this._redisConnection;
} public string GetValue(string key)
{
return _redisConnection.GetDatabase().StringGet(key);
} public void SetValue(string key, object value,TimeSpan time)
{
if (value!=null)
{
_redisConnection.GetDatabase().StringSet(key,JsonConvert.SerializeObject(value),time);
}
} public void Clear()
{
foreach (var endPoint in this.ConnectionRedis().GetEndPoints())
{
var server = this.ConnectionRedis().GetServer(endPoint);
foreach (var key in server.Keys())
{
_redisConnection.GetDatabase().KeyDelete(key);
}
}
} public bool Get(string key)
{
return _redisConnection.GetDatabase().KeyExists(key);
} public TEntity Get<TEntity>(string key)
{
var value = _redisConnection.GetDatabase().StringGet(key);
if (value.HasValue)
{
//需要用的反序列化,将Redis存储的Byte[],进行反序列化
return JsonConvert.DeserializeObject<TEntity>(value);
}
else
{
return default(TEntity);
}
} public void Remove(string key)
{
_redisConnection.GetDatabase().KeyDelete(key);
} public bool SetValue(string key, byte[] value)
{
return _redisConnection.GetDatabase().StringSet(key, value, TimeSpan.FromSeconds(120));
} public async Task ClearAsync()
{
foreach (var endPoint in this.ConnectionRedis().GetEndPoints())
{
var server = this.ConnectionRedis().GetServer(endPoint);
foreach (var key in server.Keys())
{
await _redisConnection.GetDatabase().KeyDeleteAsync(key);
}
}
} public async Task<bool> GetAsync(string key)
{
return await _redisConnection.GetDatabase().KeyExistsAsync(key);
} public async Task<string> GetValueAsync(string key)
{
return await _redisConnection.GetDatabase().StringGetAsync(key);
} public async Task<TEntity> GetAsync<TEntity>(string key)
{
var value = await _redisConnection.GetDatabase().StringGetAsync(key);
if (value.HasValue)
{
return JsonConvert.DeserializeObject<TEntity>(value);
}
else
{
return default;
}
} public async Task RemoveAsync(string key)
{
await _redisConnection.GetDatabase().KeyDeleteAsync(key);
} public async Task RemoveByKey(string key)
{
var redisResult = await _redisConnection.GetDatabase().ScriptEvaluateAsync(LuaScript.Prepare(
//模糊查询:
" local res = redis.call('KEYS', @keypattern) " +
" return res "), new { @keypattern = key }); if (!redisResult.IsNull)
{
var keys = (string[])redisResult;
foreach (var k in keys)
_redisConnection.GetDatabase().KeyDelete(k); }
} public async Task SetAsync(string key, object value, TimeSpan cacheTime)
{
if (value != null)
{
await _redisConnection.GetDatabase().StringSetAsync(key, JsonConvert.SerializeObject(value), cacheTime);
}
} public async Task<bool> SetValueAsync(string key, byte[] value)
{
return await _redisConnection.GetDatabase().StringSetAsync(key, value, TimeSpan.FromSeconds(120));
}
}

5.启动项目新增对Ysq.Core.Redis项目的引用,并且注入Redis类库中的接口

6.在控制器中设置一对key/value,然后进行读取并返回

Redis客户端有内容

另外:

Redis分布式锁是一种利用Redis单线程特性以及操作原子性实现分布式系统中锁功能的机制,以下我来详细解释这张图和Redis分布式锁的原理:

分布式锁的基本概念:

●使用 SET key value EX seconds NX 命令:key: 锁的名称。

○value: 锁的值(可以用来区分客户端)。

○EX seconds: 锁的过期时间(秒),保证锁不会无限存在。

○NX: 表示“仅在键不存在时设置”(即防止重复设置锁)。

●原理:当某个客户端成功设置了锁后,其他客户端如果尝试设置同样的锁(同样的 key),会失败,直到锁过期或者被释放。

左侧客户端操作:

1.set lock true ex 60 nx:尝试创建一个名为 lock 的锁,值为 true,过期时间为 60 秒。返回 OK,说明锁成功创建。

2.尝试 set lock true ex 60 nx 再次设置锁,返回 (nil),说明锁已经存在,无法再次创建。

3.删除锁:del lock,返回 (integer) 1,表示成功删除锁。

4.再次尝试创建锁:set lock true ex 60 nx,返回 OK,锁被重新创建。

5.删除锁:del lock,返回 (integer) 1。

右侧客户端操作:

1.set lock true ex 60 nx:尝试设置锁。如果锁不存在,返回 OK,锁被设置。

2.再次设置锁:set lock true ex 60 nx,返回 (nil),说明锁已存在,当前客户端无法设置。

3.删除锁:del lock,返回 (integer) 1,锁被成功删除。

观察:

●当锁存在时,其他客户端的 SET lock ... NX 操作会失败。

●但删除锁是无条件的,任何客户端都可以执行 DEL lock 操作,这种情况下存在并发删除的风险。

Redis分布式锁的主要目的是在分布式系统中,确保同一时刻只有一个客户端对某一关键资源进行操作,避免“同时修改”导致数据不一致的问题。例如:

●限制同一资源的并发访问(如用户订单、库存操作)。

●避免定时任务的多次重复执行。

使用锁的伪代码分析:

以下伪代码演示了Redis分布式锁的使用过程:

点击查看代码
If (exists(lock)) {
return false; // 锁存在,返回失败
} else {
set lock true ex 5 nx; // 设置锁(超时时间为5秒)
// 开始操作关键资源
set key1 100; // 资源操作,比如设置值为100
del lock; // 删除锁
return true; // 返回成功
}

(八).NET6.0添加通用的Redis功能的更多相关文章

  1. C# 9.0 添加和增强的功能【基础篇】

    一.记录(record) C# 9.0 引入了记录类型. 可使用 record 关键字定义一个引用类型,以最简的方式创建不可变类型.这种类型是线程安全的,不需要进行线程同步,非常适合并行计算的数据共享 ...

  2. C# 8.0 添加和增强的功能【基础篇】

    .NET Core 3.x和.NET Standard 2.1支持C# 8.0. 一.Readonly 成员 可将 readonly 修饰符应用于结构的成员,来限制成员为不可修改状态.这比在C# 7. ...

  3. C# 6.0 添加和增强的功能【基础篇】

    C# 6.0 是在 visual studio 2015 中引入的.此版本更多关注了语法的改进,让代码更简洁且更具可读性,使编程更有效率,而不是和前几个版本一样增加主导性的功能. 一.静态导入 我们都 ...

  4. C# 7.0 添加和增强的功能【基础篇】

    C# 7.0 版是与 Visual Studio 2017 一起发布. 虽然该版本继承和发展了C# 6.0,但不包含编译器即服务. 一.out 变量 以前我们使用out变量必须在使用前进行声明,C# ...

  5. 手把手教会 VS2022 设计 Winform 高DPI兼容程序 (net461 net6.0 双出)

    本文主要解决两个问题 C# Winform高DPI字体模糊. 高DPI下(缩放>100%), UI设计器一直提示缩放到100%, 如果不重启到100%,设计的控件会乱飞. 建立测试程序 新建.N ...

  6. Vue2.0的通用组件

    饿了么基于Vue2.0的通用组件开发之路(分享会记录)   Element:一套通用组件库的开发之路 Element 是由饿了么UED设计.饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库. ...

  7. .net core2.0添加json文件并转化成类注入控制器使用 让js调试更简单—console

    .net core2.0添加json文件并转化成类注入控制器使用 上一篇,我们介绍了如何读取自定义的json文件,数据是读取出来了,只是处理的时候太麻烦,需要一遍一遍写,很枯燥.那么有没有很好的办法呢 ...

  8. .NET微服务系统迁移至.NET6.0的故事

    本次迁移涉及的是公司内部一个业务子系统,该系统是一个多样化的应用,支撑着公司的多个业务方向.目前,该系统由40多个基于.NET的微服务应用构成,使用数千个CPU核心和数TB内存,在数百个Linux容器 ...

  9. WCF学习之旅—WCF4.0中的简化配置功能(十五)

    六 WCF4.0中的简化配置功能 WCF4.0为了简化服务配置,提供了默认的终结点.绑定和服务行为.也就是说,在开发WCF服务程序的时候,即使我们不提供显示的 服务终结点,WCF框架也能为我们的服务提 ...

  10. 解析大型.NET ERP系统 通用附件管理功能

    大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...

随机推荐

  1. Java常见面试真题之中级进阶(HashMap篇)

    前言 本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!说说Hashtable 与 HashMap 的区别?HashMap 中的 key 我们可以使用任何类作为 key 吗?HashMap 的长 ...

  2. 《机器学习实战》(Machine Learning in Action)

    地址: https://www.manning.com/books/machine-learning-in-action 代码地址: https://www.manning.com/downloads ...

  3. 3.17 Linux移动或重命名文件和目录(mv命令)

    mv 命令(move 的缩写),既可以在不同的目录之间移动文件或目录,也可以对文件和目录进行重命名.该命令的基本格式如下: [root@localhost ~]# mv [选项] 源文件 目标文件 选 ...

  4. FPGA时序约束基础

    一.时序约束的目的 由于实际信号在FPGA内部期间传输时,由于触发器等逻辑期间并非理想期间,因此不可避免地存在传输延时,这种延迟在高速工作频率.高逻辑级数时会造成后级触发器地建立时间和保持时间不满足, ...

  5. CLIPFit:不绕弯子,直接微调比提示微调和适配器微调更好 | EMNLP'24

    来源:晓飞的算法工程笔记 公众号,转载请注明出处 论文: Vision-Language Model Fine-Tuning via Simple Parameter-Efficient Modifi ...

  6. Python新手教学

    ## 简介Python是一种简单易学的编程语言,广泛应用于各个领域,包括Web开发.数据科学.人工智能等.本文将为新手程序员提供Python基础知识的教学,包括变量.数据类型.条件语句.循环.函数等内 ...

  7. 强化学习算法中log_det_jacobian的影响是否需要考虑

    相关: 人形机器人-强化学习算法-PPO算法的实现细节是否会对算法性能有大的影响. https://openi.pcl.ac.cn/devilmaycry812839668/google_brax_p ...

  8. 解密prompt系列43. LLM Self Critics

    前一章我们介绍了基于模型自我合成数据迭代,来提升LLM生成更合理的自我推理思考链路.但在模型持续提升的道路上,只提升Generator能力是不够的,需要同步提升Supervisor.Verifier的 ...

  9. JVM最简生存指南

    本文由 ImportNew - Grey 翻译自 hadihariri.欢迎加入Java小组.转载请参见文章末尾的要求. 最近更新 : 2014年1月9日 为什么要写这个指南 持续更新 目标人群 基础 ...

  10. 优秀的 Java 程序员所应该知道的 Java 知识

    JDK 相关知识 JDK 的使用 JDK 源代码 JDK 相应技术背后的原理 JVM 相关知识 服务器端开发需要重点熟悉的 Java 技术 Java 并发 Java IO 开源框架 Java 之外的知 ...