C# Redis分布式锁

news2024/12/22 9:52:13

使用包StackExchange.Redis,可以在NuGet中下载到

可以支持多并发请求,保持数据一致性和不重复已经保证代码只再一次请求结束后再执行

public static async Task<bool> TryAcquireLockAsync()
{
    bool isAcquired = false;
    while (!isAcquired)
    {
        isAcquired = await _redisConn.GetDatabase().LockTakeAsync(_lockKey, "my_lock_instance", LockTimeout);
        if (!isAcquired)
        {
            // 没有获取到锁,可以在这里等待一段时间再尝试
            await Task.Delay(100); // 等待100毫秒
        }
    }
    return isAcquired;
}

public static async Task ReleaseLockAsync()
{
    await _redisConn.GetDatabase().LockReleaseAsync(_lockKey, "my_lock_instance");
}
/// <summary>
/// 获取锁
/// </summary>
/// <returns></returns>
public static bool TryAcquireLock()
{
    bool isAcquired = false;
    while (!isAcquired)
    {
        isAcquired = _redisConn.GetDatabase().LockTake(_lockKey, "my_lock_instance", LockTimeout);
        if (!isAcquired)
        {
            // 没有获取到锁,可以在这里等待一段时间再尝试
            Task.Delay(100); // 等待100毫秒
        }
    }
    return isAcquired;
}
/// <summary>
/// 释放锁
/// </summary>
public static void ReleaseLock()
{
    _redisConn.GetDatabase().LockReleaseAsync(_lockKey, "my_lock_instance");
}

本次代码使用在生成唯一Code的使用:
redis主要代码

    //锁主要参数
    private static readonly object Locker = new object();
    private static ConnectionMultiplexer _redisConn;
    private static readonly string LockKey = "redis_lock";
    private static string _lockKey;
    private static readonly TimeSpan AcquireTimeout = TimeSpan.FromSeconds(10);
    private static readonly TimeSpan LockTimeout = TimeSpan.FromSeconds(30);
    //配置参数
    public static string RedisIp = AppConfigurtaionServices.Configuration["RedisSetting:Host"];
    public static string RedisPort = AppConfigurtaionServices.Configuration["RedisSetting:Port"];
    public static string RedisPwd = AppConfigurtaionServices.Configuration["RedisSetting:PassWord"];
    private static ConfigurationOptions ConfigurationOptions = ConfigurationOptions.Parse($"{RedisIp}:{RedisPort},allowAdmin=true{(RedisPwd.IsNullOrEmpty() ? "" : $",{RedisPwd}")}");
    /// <summary>
    /// 单例获取
    /// </summary>
    public static ConnectionMultiplexer RedisConn
    {
        get
        {
            if (_redisConn == null)
            {
                InitConfiguration();
                // 锁定某一代码块,让同一时间只有一个线程访问该代码块
                lock (Locker)
                {
                    if (_redisConn == null || !_redisConn.IsConnected)
                    {
                        _redisConn = ConnectionMultiplexer.Connect(ConfigurationOptions);
                    }
                }
                _lockKey = LockKey;
            }

            return _redisConn;
        }
    }

    public static void InitConfiguration()
    {
        string password = RedisPwd.IsNullOrEmpty() ? "" : $",password ={RedisPwd}";
        ConfigurationOptions = ConfigurationOptions.Parse($"{RedisIp}:{RedisPort},allowAdmin=true{password}");//
    }

    /// <summary>
    /// 设置定时过期redis key
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="expireTime">过期时间 分钟</param>
    /// <param name="dbs">redis db 默认db(1)</param>
    public static void SetRedisExpireKey(string key, int expireTime, int dbs = 1)
    {
        //将订单和时间存住到redis中,走定时执行任务
        TimeSpan expiry = TimeSpan.FromSeconds(expireTime * 60);
        var db = _redisConn.GetDatabase(dbs);
        db.StringSet($"{key}", ""
        , expiry);
    }

    /// <summary>
    /// 删除定时过期redis key
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="dbs">redis db默认db(1)</param>
    public static void DeleteRedisExpireKey(string key, int dbs = 1)
    {
        var db = _redisConn.GetDatabase(dbs);
        db.KeyDelete($"{key}");
    }


    #region Redis方法
    public static bool Exists(string key)
    {
        var db = _redisConn.GetDatabase();
        return db.KeyExists(key);
    }

    public static bool Exists(string key, int dbs = 0)
    {
        var db = _redisConn.GetDatabase(dbs);
        return db.KeyExists(key);
    }

    public static string Get(string key)
    {
        var db = _redisConn.GetDatabase();
        return db.StringGet(key);
    }
    public static bool Set(string key, string value)
    {
        var db = _redisConn.GetDatabase();
        return db.StringSet(key, value);
    }
    public static bool SetStr(string key, string value, int dbs = 0)
    {
        var db = _redisConn.GetDatabase(dbs);
        return db.StringSet(key, value);
    }
    public static string SetStrDelete(string key, int dbs = 0)
    {
        //将订单和时间存住到redis中,走定时执行任务
        var db = _redisConn.GetDatabase(dbs);
        return db.StringGetDelete(key);
    }
    public static bool Set(string key, string value, int expireTime)
    {
        //将订单和时间存住到redis中,走定时执行任务
        TimeSpan expiry = TimeSpan.FromSeconds(expireTime * 60);
        var db = _redisConn.GetDatabase();
        return db.StringSet(key, value, expiry);
    }
    public static string SetStrDelete(string key)
    {
        //将订单和时间存住到redis中,走定时执行任务
        var db = _redisConn.GetDatabase();
        return db.StringGetDelete(key);
    }
    public static bool RemoveKey(string key)
    {
        var db = _redisConn.GetDatabase();
        return db.KeyDelete(key);
    }
    public static bool RemoveKey(string key, int dbs = 0)
    {
        var db = _redisConn.GetDatabase(dbs);
        return db.KeyDelete(key);
    }
    public static bool HashSet(string redisName, string key, string value)
    {
        var db = _redisConn.GetDatabase();
        return db.HashSet(redisName, key, value);

    }

    public static bool HashSet(string redisName, string key, string value, int dbs = 0)
    {
        var db = _redisConn.GetDatabase(dbs);
        return db.HashSet(redisName, key, value);

    }

    public static string HashGet(string redisName, string key)
    {
        var db = _redisConn.GetDatabase();
        return db.HashGet(redisName, key);
    }

    public static string HashGet(string redisName, string key, int dbs = 0)
    {
        var db = _redisConn.GetDatabase(dbs);
        return db.HashGet(redisName, key);
    }

    public static bool HashRemove(string redisName, string key)
    {
        var db = _redisConn.GetDatabase();
        return db.HashDelete(redisName, key);
    }
    public static bool HashKeyExists(string redisName, string key)
    {
        var db = _redisConn.GetDatabase();
        return db.HashExists(redisName, key);
    }
    public static IEnumerable<string> GetPageList(string hashKey,int pageIndex ,int pageSize)
    {
        var db = _redisConn.GetDatabase();
        var start=(pageIndex - 1) * pageSize;
        var end = pageIndex * pageSize-1;
        var values= db.ListRange(hashKey, start, end);
        return values.Select(x=>x.ToString());
    }
    

    public static bool HashKeyExists(string redisName, string key, int dbs = 0)
    {
        var db = _redisConn.GetDatabase(dbs);
        return db.HashExists(redisName, key);
    }


    #endregion

    public static async Task<bool> TryAcquireLockAsync()
    {
        bool isAcquired = false;
        while (!isAcquired)
        {
            isAcquired = await _redisConn.GetDatabase().LockTakeAsync(_lockKey, "my_lock_instance", LockTimeout);
            if (!isAcquired)
            {
                // 没有获取到锁,可以在这里等待一段时间再尝试
                await Task.Delay(100); // 等待100毫秒
            }
        }
        return isAcquired;
    }

    public static async Task ReleaseLockAsync()
    {
        await _redisConn.GetDatabase().LockReleaseAsync(_lockKey, "my_lock_instance");
    }
    /// <summary>
    /// 获取锁
    /// </summary>
    /// <returns></returns>
    public static bool TryAcquireLock()
    {
        bool isAcquired = false;
        while (!isAcquired)
        {
            isAcquired = _redisConn.GetDatabase().LockTake(_lockKey, "my_lock_instance", LockTimeout);
            if (!isAcquired)
            {
                // 没有获取到锁,可以在这里等待一段时间再尝试
                Task.Delay(100); // 等待100毫秒
            }
        }
        return isAcquired;
    }
    /// <summary>
    /// 释放锁
    /// </summary>
    public static void ReleaseLock()
    {
        _redisConn.GetDatabase().LockReleaseAsync(_lockKey, "my_lock_instance");
    }
}

调用方式:

 /// <summary>
 /// 获取新的条形码刷新数据,分布式控制
 /// </summary>
 /// <param name="orgCode"></param>
 public static void SetOneTicketBarCode(string orgCode)
 {
     try
     {
         DateTime nowTime = DateTime.Now;
         string StartTime = nowTime.AddSeconds(-5).ToString("yyyy-MM-dd HH:mm:ss");
         string EndTime = nowTime.AddSeconds(5).ToString("yyyy-MM-dd HH:mm:ss");
         var isLockAcquired = RedisHelper.TryAcquireLock();
         if (isLockAcquired)
         {
             DataSet set = EntityBase.GetDB().GetDS($"select Code from MemberTicket where orgCode='{orgCode}' and TicketState in (0,1,3) and (BarCode is null or BarCode='') and crDate>='{StartTime}' and crDate<='{EndTime}';" +
                 $"select Code,BarCode from MemberTicket where orgCode='{orgCode}' and TicketState in (0,1,3) and crDate>='{StartTime}' and crDate<='{EndTime}';" +
                 $"select Code,BarCode from MemberTicket where orgCode='{orgCode}' and TicketState in (0,1,3) and (BarCode is null or BarCode='') and crDate>='{StartTime}' and crDate<='{EndTime}';");
             if (set.Tables[0].Rows.Count > 0)
             {
                 var dt = set.Tables[1];
                 var dthas = set.Tables[2];
                 List<string> list = new List<string>();
                 foreach (DataRow item in dthas.Rows)
                 {
                     if (!item.GetStringValue("BarCode").IsNullOrEmpty())
                     {
                         continue;
                     }
                     string BarCode = DateTime.Now.ToString("hmmssfff");
                     BarCode = (Convert.ToInt32(BarCode) + new Random().Next(0, 99999)).ToString();
                     while (list.Contains(BarCode))
                     {
                         BarCode = (Convert.ToInt32(BarCode) + new Random().Next(0, 99999)).ToString();
                     }
                     while (dt.AsEnumerable().Any(x => x.Field<string>("BarCode") == BarCode))
                     {
                         BarCode = (Convert.ToInt32(BarCode) + new Random().Next(0, 99999)).ToString();
                     }
                     list.Add(BarCode);
                     EntityBase entityBase = new EntityBase("MemberTicket");
                     entityBase.DoType = "Update";
                     entityBase.FieldValueList.Add("Code", new FieldValue() { Name = "Code", CurrentValue = item.GetStringValue("Code") });
                     entityBase.FieldValueList.Add("BarCode", new FieldValue() { Name = "BarCode", CurrentValue = BarCode });
                     entityBase.AddOrUpdate();
                 }
             }
         }
         else
         {

         }
     }
     catch (Exception ex)
     {
         ErrorLogs.InsertErrorLog(LogType.Error, "生成条形码报错:" + ex.ToString());
     }
     finally
     {
         RedisHelper.ReleaseLock();
     }
 }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3组件封装技巧与心得

摘要&#xff1a; 日常开发中&#xff0c;用Vue组件进行业务拆分&#xff0c;代码解耦是一个很好的选择&#xff1b; 今天就来分享一下我在使用Vue3进行组件封装的一些技巧和心得&#xff0c;希望能够帮助到大家&#xff1b; 1. 组件特性&#xff1a; 在Vue中组件是一个独立的…

图漾相机-ROS1_SDK_ubuntu版本编译(新版本)

文章目录 官网编译文档链接官网SDK下载链接1、下载 Camport ROS1 SDK1.下载git2、下载链接 2、准备编译工作1、安装 catkin2、配置环境变量3. 将Camport3中的linux库文件拷贝到 user/lib目录下4、修改lunch文件制定相机&#xff08;可以放在最后可以参考在线文档&#xff09;**…

十二、从0开始卷出一个新项目之瑞萨RZN2L 基于IAR coremark fsp200工程构建和iar icf链接文件修改方法

目录 一、概述 二、rzn2l_fsp2.0.0_coremark工程构建 2.1 目录结构 2.2 项目一览 2.3 iar工程打开报错如何处理 三、代码优化的问题 3.1 system.c中复制内存 3.2 iar代码优化等级与volatile关键字 3.3 iar配置优化单个文件与预编译宏的范围 四、iar .icf链接文件修改…

内容与资讯API优质清单

作为开发者&#xff0c;拥有一套API合集是必不可少的。这个开发者必备的API合集汇集了各种实用的API资源&#xff0c;为你的开发工作提供了强大的支持&#xff01;无论你是在构建网站、开发应用还是进行数据分析&#xff0c;这个合集都能满足你的需求。你可以通过这些免费API获…

线程知识总结(二)

本篇文章以线程同步的相关内容为主。线程的同步机制主要用来解决线程安全问题&#xff0c;主要方式有同步代码块、同步方法等。首先来了解何为线程安全问题。 1、线程安全问题 卖票示例&#xff0c;4 个窗口卖 100 张票&#xff1a; class Ticket implements Runnable {priv…

多智能体/多机器人网络中的图论法

一、引言 1、网络科学至今受到广泛关注的原因&#xff1a; &#xff08;1&#xff09;大量的学科&#xff08;尤其生物及材料科学&#xff09;需要对元素间相互作用在多层级系统中所扮演的角色有更深层次的理解&#xff1b; &#xff08;2&#xff09;科技的发展促进了综合网…

OB删除1.5亿数据耗费2小时

目录 回顾&#xff1a;mysql是怎么删除数据的&#xff1f; 删除方案 代码实现 执行结果 结论 本篇是实际操作 批量处理数据以及线程池线程数设置 记录学习 背景&#xff1a;有一张用户标签表&#xff0c;存储数据量达4个亿&#xff0c;使用OceanBase存储&#xff0c;由于…

简洁IIC协议讲述

目录 一&#xff1a;首先&#xff0c;IIC传输是在2条线上传输的。 二&#xff1a;时钟信号的频率和占空比解释&#xff08;可以看作PWM波形&#xff09; 三&#xff1a;传输信号的流程图&#xff08;起始和终止信号都是由主机(我)控制&#xff09; 四&#xff1a;开始信号和…

IIC I2C子协议 SMBus协议 通信协议原理 时序 SMBus深度剖析

引言&#xff1a;系统管理总线&#xff08;SMBus&#xff09;是一种双线接口&#xff0c;通过该接口&#xff0c;各种系统组件芯片和设备可以相互以及与系统其他部分通信。它基于IC总线的操作原理。附录B提供了一些SMBus特性与IC总线不同的方式的描述。 SMBus为系统和电源管理相…

重拾设计模式--建造者模式

文章目录 建造者模式&#xff08;Builder Pattern&#xff09;概述建造者模式UML图作用&#xff1a;建造者模式的结构产品&#xff08;Product&#xff09;&#xff1a;抽象建造者&#xff08;Builder&#xff09;&#xff1a;具体建造者&#xff08;Concrete Builder&#xff…

Orleans异常传递测试

Orleans具备非常简单的异常传递机制&#xff0c;Grain或Placement注解逻辑抛异常&#xff0c;可以直接传递到客户端&#xff0c;测试代码如下&#xff1a; 首先在客户端、Silo服务程序的Main方法增加ThreadException事件处理函数&#xff0c;避免未处理异常导致进程闪退。 sta…

【Linux进程】基于管道实现进程池

目录 前言 1. 进程池 1.1 基本结构&#xff1a; 1.2. 池化技术 1.3. 思路分析 1.4. 代码实现 总结 前言 上篇文章介绍了管道及其使用&#xff0c;本文在管道的基础上&#xff0c;通过匿名管道来实现一个进程池&#xff1b; 1. 进程池 父进程创建一组子进程&#xff0c;子进…

PCL点云库入门——PCL库中点云数据拓扑关系之K-D树(KDtree)

1、点云的拓扑邻域 在三维空间数据处理的领域中&#xff0c;点云的邻域概念显得尤为关键&#xff0c;它不仅链接了点云数据之间的拓扑结构&#xff0c;而且在构建点云间的拓扑关系时起到了桥梁的作用。这种关系的建立&#xff0c;使得我们能够以一种高效、迅速的方式管理庞大的…

Leecode刷题C语言之根据第k场考试的分数排序

执行结果:通过 执行用时和内存消耗如下&#xff1a; int gk 0;int compare(const void* a, const void* b) {int* ua *(int**)a;int* ub *(int**)b;return ub[gk] - ua[gk]; }int** sortTheStudents(int** score, int scoreSize, int* scoreColSize, int k, int* returnSiz…

由popover框一起的操作demo问题

场景&#xff1a; 当popover框弹出的时候&#xff0c;又有MessageBox 提示&#xff0c;此时关闭MessageBox 提示&#xff0c;popover就关闭了。将popover改为手动激活&#xff0c;可以解决这个问题&#xff0c;但是会引起另外一个问题&#xff0c;之前&#xff08;click触发的时…

QT修改运行窗口的图标

首先&#xff0c;在.pro下添加两行&#xff1a; Debug:DESTDIR $$PWD Release:DESTDIR $$PWD 指定目标文件的路径 指定生成的debug和release文件夹路径在当前项目下 上面是为了防止爆奇怪的错 右键项目添加新文件 选择QT-》QT Resource File 起个名&#xff0c;然后下一步…

降低Mobx技术债问题-React前端数据流方案调研整理

我们现在主要是使用Mobx&#xff0c;但是Mobx的易于上手和灵活度也带来了很多预期以外的问题&#xff0c;随着项目的增长我们的代码技术债变得愈加沉重&#xff0c;不同的模块杂糅一起、单一store无限膨胀。 为此我们的调研是希望能找到一个更好的state配置、数据流的约定方案。…

sql server索引优化语句

第一步 建一个测试表 --create table TestUsers --( -- Id int primary key identity(1,1), -- Username varchar(30) not null, -- Password varchar(10) not null, -- CreateDateTime datetime not null --)第二步 插入100w数据 大概1分钟执行时间 ----插入数据…

aioice里面candidate固定UDP端口测试

环境&#xff1a; aioice0.9.0 问题描述&#xff1a; aioice里面candidate固定UDP端口测试 解决方案&#xff1a; /miniconda3/envs/nerfstream/lib/python3.10/site-packages/aioice import hashlib import ipaddress import random from typing import Optional import…

Java(二十五)final关键字

Java中的final关键字在编写程序中,比较常用。尤其是在上文中的匿名内部类中。 final 表示最终,也可以称为完结器,表示对象是最终形态的,不可改变的意思。 使用final修饰的的类,是“断子绝孙”的。 一:final修饰成员变量 Final修饰的类的成员变量是常量,不可被改变。 …