Redis分布式锁防止缓存击穿

news/2025/3/15 17:25:11/文章来源:https://www.cnblogs.com/daiwk/p/18343446

一、Nuget引入 StackExchange.RedisDistributedLock.Redis依赖

二、使用 StackExchange.Redis 对redis操作做简单封装

public class RedisHelper
{
private static ConnectionMultiplexer _redis;
private static string _connectionString;// 静态构造函数,确保在程序启动时初始化连接
static RedisHelper()
{
_connectionString = "127.0.0.1:6379,password=ist123$%^"; // 替换为你的Redis服务器地址和端口,例如:"localhost:6379"
_redis = ConnectionMultiplexer.Connect(_connectionString);
}// 获取数据库实例
public static IDatabase GetDatabase()
{
return _redis.GetDatabase();
}// 字符串设置与获取
public static void SetString(string key, string value)
{
GetDatabase().StringSet(key, value);
}public static string GetString(string key)
{
return GetDatabase().StringGet(key);
}// 哈希设置与获取
public static void SetHashField(string key, string field, string value)
{
GetDatabase().HashSet(key, field, value);
}public static string GetHashField(string key, string field)
{
return GetDatabase().HashGet(key, field);
}// 列表操作
public static long ListRightPush(string key, string value)
{
return GetDatabase().ListRightPush(key, value);
}public static string ListLeftPop(string key)
{
return GetDatabase().ListLeftPop(key);
}// 集合操作
public static bool SetAdd(string key, string value)
{
return GetDatabase().SetAdd(key, value);
}public static bool SetRemove(string key, string value)
{
return GetDatabase().SetRemove(key, value);
}public static bool SetContains(string key, string value)
{
return GetDatabase().SetContains(key, value);
}// 键的其他操作
public static bool KeyExists(string key)
{
return GetDatabase().KeyExists(key);
}public static void Remove(string key)
{
GetDatabase().KeyDelete(key);
}// 异步方法示例
public static async Task SetStringAsync(string key, string value)
{
await GetDatabase().StringSetAsync(key, value);
}public static async Task<string> GetStringAsync(string key)
{
return await GetDatabase().StringGetAsync(key);
}// 关闭连接(通常在应用程序关闭时调用)
public static void CloseConnection()
{
if (_redis != null && _redis.IsConnected)
{
_redis.Close();
_redis.Dispose();
}
}}

 

三、模拟从Redis获取缓存数据的逻辑

/// <summary>
/// 模拟操作
/// </summary>
public class RedisOper
{public static string GetDataByRedis(string RedisKey){string ThreadId = Thread.GetCurrentProcessorId().ToString();string data = string.Empty;//从redis读数据if (RedisHelper.KeyExists(RedisKey)){data = RedisHelper.GetString(RedisKey);Console.WriteLine($"查询到缓存数据:{data}    线程ID:{ThreadId}");}else{Console.WriteLine($"未查询到缓存数据,准备从数据库查询存入缓存     线程ID:{ThreadId}");//模拟从数据库查询存入redis,使用分布式锁,只允许一个请求完成var redisDistributedLock = new RedisDistributedLock("lockkey", RedisHelper.GetDatabase());Console.WriteLine($"尝试获取锁     线程ID:{ThreadId}");using (redisDistributedLock.Acquire()){//再次判断是否存在缓存if (!RedisHelper.KeyExists(RedisKey)){Console.WriteLine($"获取到锁,模拟将数据库数据写入缓存     线程ID:{ThreadId}");var GetDataByDB = "This is test data";RedisHelper.SetString(RedisKey, GetDataByDB);Thread.Sleep(2000);}}}return data;}public static async Task<string> GetDataByRedisAsync(string RedisKey){Console.WriteLine($"当前线程ID:{Thread.GetCurrentProcessorId()}");string data = string.Empty;//从redis读数据if (RedisHelper.KeyExists(RedisKey)){data = await RedisHelper.GetStringAsync(RedisKey);Console.WriteLine($"查询到缓存数据:{data}");}else{Console.WriteLine($"未查询到缓存数据,准备从数据库查询存入缓存");//模拟从数据库查询存入redis,使用分布式锁,只允许一个请求完成var redisDistributedLock = new RedisDistributedLock("lockkey", RedisHelper.GetDatabase());Console.WriteLine($"尝试获取锁 ");using (redisDistributedLock.Acquire()){//再次判断是否存在缓存if (!RedisHelper.KeyExists(RedisKey)){Console.WriteLine("获取到锁,模拟将数据库数据写入缓存");var GetDataByDB = "This is test data";await RedisHelper.SetStringAsync(RedisKey, GetDataByDB);await Task.Delay(2000);}}}return data;}
}

 

四、测试

string redisKey = "testData";
RedisHelper.Remove(redisKey);
//模拟10个线程同时去获取Redis缓存
List<Task> tasksList= new List<Task>();
tasksList.Add(Task.Run(()=>RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
tasksList.Add(Task.Run(() => RedisOper.GetDataByRedis(redisKey)));
Task.WaitAll(tasksList.ToArray());
await Task.Run(() => RedisOper.GetDataByRedis(redisKey));

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/778188.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新西兰 WHV 打工度假签证 All In One

新西兰 WHV 打工度假签证 All In One New Zealand WHV (Working Holiday Visas)新西兰 WHV 打工度假签证 All In OneNew Zealand WHV (Working Holiday Visas)打工度假常见问题答疑我们为你整理一些关于新西兰打工度假签证的常见问题及解答,希望能够帮助准备中的你。我该如何申…

词云图大师(WordCloudMaster)上线Web端!

我们非常激动地宣布,词云图大师(WordCloudMaster)现已正式上线Web端!这一全新版本为用户带来了更多的便捷和功能,让创建和分享词云变得更加轻松。无论是企业、教育机构还是个人用户,都可以通过Web端实现快速生成和定制属于自己的词云图。 https://studio.wordcloudmaster…

图表全能王(ChartStudio) 上架VisionPro!

图表全能王(ChartStudio) - 终极图表制作工具!支持条形图、折线图、面积图、柱形图、条形图、饼图、玫瑰图、雷达图、牛肉图、风琴图、旭日图、桑基图等图表。 https://apps.apple.com/app/chartstudio-data-analysis/id6474099675 https://apps.apple.com/cn/app/%E5%9B%BE%E…

H5页面能否获取手机的ip

在HTML5中,出于安全和隐私的考虑,浏览器不允许网页直接访问设备的本地IP地址。不过,可以通过一些方法间接获取到用户的公网IP地址,但这些方法通常依赖于服务器端的配合。 以下是几种获取用户公网IP地址的方法: 1. 使用WebRTC WebRTC(Web Real-Time Communications)提供了…

异常类型结构图

异常类型结构图 目录异常类型结构图异常类型结构图Error和Exception的区别Error和Exception的联系Error和Exception的区别 异常类型结构图Error和Exception的区别 Error和Exception的联系继承结构:Error和Exception都是继承于Throwable,RuntimeException继承自Exception。 Er…

Typecho在Ubuntu 22.04上的安装部署

本文介绍了Typecho在Ubuntu 22.04上的安装和配置安装Nginx并配置访问 安装PHP并输出脚本结果 配置typechoNginx安装并验证 apt install nginx systemctl start nginx正常情况应该可以看到Nginx的欢迎页面了,如果看不到就是防火墙的问题,设置下防火墙放通即可。 安装PHP并使用…

003.flask与Mysql的连接以及增删改查

Flask与Mysql的连接以及在Flask中对数据库进行增删改查python解释器:3.8.3版本 flask==2.2.2版本 flask_sqlalchemy=3.1.1 flask_migrate==4.0.71.创建文件并且配置创建一个大文件在该文件中进行创建static(静态),templates(动态文件),app.py文件将大文件移到vscode软件中(py…

结构开发笔记(一):外壳IP防水等级与IP防水铝壳体初步选型

前言做产品,需要选型外壳结构,本篇普及IP防护等级与基础铝合金外壳。 IPXX防护等级IP等级(Ingress Protection rating)是用于描述电气设备外壳对异物(如尘埃、手指或其他固体物体)和水侵入的防护能力的国际标准。这个标准在全球范围内被广泛应用,以确保设备在各种环境条…

【YashanDB数据库】自关联外键插入数据时报错:YAS-02033 foreign key constraint violated parent key not found

问题现象 使用如下的sql语句创建自关联外键表: drop table self_f_key; create table self_f_key(t1 number primary key not null, t2 number); create index i_s_1 on self_f_key(t2); alter table self_f_key add constraint c_0001 foreign key(t2) references self_f_key…

《DNK210使用指南 -CanMV版 V1.0》第十七章 machine.WDT类实验

第十七章 machine.WDT类实验 1)实验平台:正点原子DNK210开发板 2)章节摘自【正点原子】DNK210使用指南 - CanMV版 V1.0 3)购买链接:https://detail.tmall.com/item.htm?&id=782801398750 4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/k210…

打造高效智能的会员预约系统

打造个性化预约体验:美业、美发、按摩与医美行业的会员预约系统构建在当今这个快节奏的社会中,美容美发、按摩放松及医美整形等服务行业迎来了前所未有的发展机遇。为了提升顾客体验,增强用户粘性,并高效管理门店运营,开发一套集会员管理、预约调度、服务定制化于一体的预…

博卡会员通小程序功能案例分析

博卡会员通小程序作为一款专为消费品行业设计的会员管理工具,其功能设计紧密围绕会员管理、用户体验提升及营销策略优化三大核心目标。以下是对其关键功能的案例分析: 一、会员精细化管理 用户画像构建 功能描述:通过收集会员的基本信息(如姓名、性别、年龄等)、消费记录、…