基于net core2.2的redis秒杀+数据持久化+数据恢复系列(2)

news2024/10/7 14:24:27

第一篇我们总结了秒杀的整个流程,本篇我们详细介绍下redis的秒杀实现,基于.net core2.2开发。

首先,需要安装redis,因为我在本地测试的,所以安装的windows版本的redis。redis分为服务端和客户端,这个redis怎么安装,本篇不详细说明,如果有安装问题和无法下载redis的windows版本的话可以私聊我。

第二步,就是编码部分,新建一个web api接口服务,使用redis的lua脚本做库存扣减,属于原子操作。大家就用下面的代码,可以支持1000个先线程的并发,在大的并发我没有测试,可能需要换架构。核心编码如下:

public string doKill(string threadId)
        {
            string tId = threadId;
            string uid = getCheckNumber(); //生成一个随机的用户id
            string prodid = "1";//商品固定001
            try
            {
                ConnectionMultiplexer redis = radisTemplate.getConn();
                IDatabase db = redis.GetDatabase();

                //定义Lua脚本
                string secKillScript = "local userid=KEYS[1];\r\n" +
                       "local prodid=KEYS[2];\r\n" +
                       "local qtkey='sk:'..prodid..\":qt\";\r\n" +
                       "local usersKey='sk:'..prodid..\":user\";\r\n" +
                       "local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" +
                       "if tonumber(userExists)==1 then \r\n" +
                       "   return 2;\r\n" +
                       "end\r\n" +
                       "local num= redis.call(\"get\" ,qtkey);\r\n" +
                       "if tonumber(num)<=0 then \r\n" +
                       "   return 0;\r\n" +
                       "else \r\n" +
                       "   redis.call(\"decr\",qtkey);\r\n" +
                       "   redis.call(\"sadd\",usersKey,userid);\r\n" +
                       "end\r\n" +
                       "return 1";

                RedisKey[] s = new RedisKey[2];
                s[0] = uid;
                s[1] = prodid;

                //使用ScriptEvaluate执行脚本
                Object result = db.ScriptEvaluate(secKillScript, s);
                string result1 = result.ToString();
                if ("0".Equals(result1))
                {
                    Log.Info($"线程:{tId}:已抢空");
                    return "已抢空!!";
                }
                else if ("1".Equals(result1))
                {
                    RequestDto requestDto = new RequestDto
                    {
                        Id = tId,
                        SuccessDate = DateTime.Now,
                        Message = $"请求成功:{tId}"
                    };
                    string str = JsonConvert.SerializeObject(requestDto);
                    db.ListLeftPushAsync("sk2", str);
                    Log.Info($"线程:{tId}:抢到了");
                    return "抢购成功!!!!";
                }
                else if ("2".Equals(result1))
                {
                    Log.Info($"线程:{tId}:该用户已抢过");
                    return "该用户已抢过!!";
                }
                else
                {
                    Log.Info($"线程:{tId}:抢购异常");
                    return "抢购异常!!";
                }
            }
            catch (Exception ex)
            {
                Log.Info($"线程:{tId}:发生错误");
                Console.WriteLine(ex);
                Log.Error($"发生错误:{ex}");
                return "系统异常!!";
            }
        }
public static String getCheckNumber()
        {
            Random rd = new Random();
            int num = rd.Next(100000, 1000000);
            return num.ToString();
        }
 ///这上面是接口代码


///这边封装的一个redis帮助类


public class RadisConn
    {
        //定义连接器
        static ConnectionMultiplexer redis = null;
        //获取连接数据库
        public ConnectionMultiplexer getConn()
        {
            try
            {
                if (redis != null && redis.IsConnected)
                {
                    //Log.Info($"redis实例有效,直接返回!");
                    return redis;
                }
                //Log.Info($"redis实例无效,开始连接服务!");
                redis = ConnectionMultiplexer.Connect("127.0.0.1:6379,password=123456,abortConnect=false");
                //if (redis.IsConnected)
                //{
                //    Log.Info($"redis 连接服务成功!");
                //}
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            return redis;
        }

    }

    public class RequestDto
    {
        public string Id { get; set; }
        public DateTime SuccessDate { get; set; }
        public string Message { get; set; }
    }

第三步,切换到redis客户端,然后设置库存 set sk:1:qt 50

第四部,用压力测试工具或者自己写一个200个任务的请求这个接口,看看库存扣减是否正常。提供一个多线程实例,代码如下:

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace HttpClient请求
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                for (int i = 0; i <40; i++)
                {
                    Task task = Task.Run(() =>
                    {
                        Console.WriteLine($"创建线程成功,当前线程号:{Task.CurrentId}");
                        SendRequest(Task.CurrentId.ToString());
                    });
                }
                Console.ReadKey();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        static void SendRequest(string threadId)
        {
            try
            {
                var url = $"https://localhost:5001/api/values/doKill?threadId="+ threadId;
                using (var client = new HttpClient())
                {
                    var content = client.GetStringAsync(url).Result;
                    //var data = JsonConvert.DeserializeObject<dynamic>(content);
                    Console.WriteLine($"线程号:{threadId}:{content}");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }
}

 

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

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

相关文章

了解Azido TAT,使用铜催化的叠氮化物反应修饰Tat肽,以下内容查看详细信息!

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ 【产品描述】 Azido-TAT中Tat肽已被证明具有优异的细胞穿透性&#xff0c;可以增强对特异性靶向疾病的诊断和 寡核苷酸的吸收。寡核苷酸通过点击化学与Tat&#xff08;一种生物学上重要的细胞穿透肽&#xff09;的共价连接…

❤ npm install 时报Error: spawn git ENOENT

❤ npm install 时报Error: spawn git ENOENT 原因&#xff1a; 主要是因为由于 git 的环境变量未设置导致&#xff0c;所以安装一下git 的环境变量就O了&#xff0c;步骤如下&#xff1a; 设置 >> 系统 >> 高级系统设置 >> 高级 >> 环境变量 >&g…

编写软件测试用例的方法,你知道多少种

1、等价类划分法 适用场景&#xff1a; 有数据输入的地方&#xff0c;就可以使用等价类划分法。如&#xff1a;输入框 测试思想&#xff1a; 从大量数据中划分范围&#xff08;等价类&#xff09;&#xff0c;然后从每个范围中挑选代表数据&#xff0c;这些代表数据要能反应…

株洲科能冲刺上市:计划募资约6亿元,实控人为赵科峰、唐燕夫妇

7月17日&#xff0c;上海证券交易所披露的信息显示&#xff0c;已对株洲科能新材料股份有限公司&#xff08;下称“株洲科能”&#xff09;发出问询函。据贝多财经了解&#xff0c;株洲科能于2023年6月21日递交招股书&#xff0c;准备在科创板上市。 本次冲刺科创板上市&#x…

springboot+mybatis-plus实现自动建表

好长时间没输出了&#xff0c;最近工作上也是太多事&#xff0c;领导动不动就拍脑门&#xff0c;那叫一个酸爽~ 工作能力的提现不但是技术或解决问题的能力上&#xff0c;还体现在要能立刻满足领导的各种需求&#xff0c;不管是哪方面的需求&#xff0c;这样才能够拍上马屁&…

IDDR和ODDR

IDDR D&#xff1a;输入双倍速率数据&#xff08;IOB输入&#xff0c;且数据在时钟的上升沿和下降沿都会发生切换&#xff0c;即一个时钟周期发送2bit数据&#xff09; CE&#xff1a;时钟使能信号&#xff08;高有效&#xff09; C&#xff1a;时钟信号 S&#xff0c;R&#x…

STM32F4_串口 IAP

目录 前言 1. IAP简介 2. APP程序起始地址设置方法 3. 中断向量表的偏移量设置 4. 如何在MDK中生成 .BIN 文件 5. APP程序生成步骤 前言 IAP&#xff0c;即在应用编程。 1. IAP简介 IAP&#xff08;In Application Programming&#xff09;即 在应用编程&#xff0c;IAP…

Apache RocketMQ5.x-消息队列体验

Apache RocketMQ5.x-消息队列体验 Apache RocketMQ 是一款低延迟、高并发、高可用、高可靠的分布式消息中间件&#xff0c;由阿里开源&#xff0c;后由阿里捐赠给Apache基金会。 本次体验的目的是从技术角度验证一下在微服架构中&#xff0c;用Apache RocketMQ做为消息队列&am…

MQTT 订阅标识符详解

为什么需要订阅标识符 在大部分 MQTT 客户端的实现中&#xff0c;都会通过回调机制来实现对新到达消息的处理。 但是在回调函数中&#xff0c;我们只能知道消息的主题名是什么。如果是非通配符订阅&#xff0c;订阅时使用的主题过滤器将和消息中的主题名完全一致&#xff0c;…

chatglm微调

chatGML 看到 【【官方教程】ChatGLM-6B 微调&#xff1a;P-Tuning&#xff0c;LoRA&#xff0c;Full parameter】 【精准空降到 15:27】 https://www.bilibili.com/video/BV1fd4y1Z7Y5/?share_sourcecopy_web&vd_sourceaa8c13cff97f0454ee41e1f609a655f1&t927 记得看…

Java Mybatis02+oracle拓展

0目录 Mybatis 02Oracle 拓展 1.Mybatis 02 创建数据库和表 创建工程 实体类 util工具类 接口方法 Resource Mapper xml文件 配置文件 测试 加入模糊查询&#xff08;根据姓名&#xff09; 测试结果 2.ParameterType语法 实战 参数为对象 参数为…

Bean 作用域与生命周期

Bean 作用域与生命周期 ​ 对于 Spring 来说&#xff0c;核心操作对象就是存和取 Bean &#xff0c;接下来就 Bean 的作用域与生命周期进行探讨。 文章目录 Bean 作用域与生命周期一、作用域的定义1.1、Bean 的6种作用域1.2、Bean作用域设置方法 二、Bean 的生命周期2.1、Bean…

【Java】Java实现微信小程序发送服务通知

文章目录 前言一、文档来源二、JAR包引入三、后端工作四、编写配置文件配置一&#xff1a;WxConfig配置二&#xff1a;WxProperties 五、代码编写 前言 在上个月接到一个需求&#xff0c;大概是需要计算一条数据的最大办理时间从而发送任务超期的微信小程序服务通知&#xff0…

怎么进行流程图制作?分享几种绘制方法

怎么进行流程图制作&#xff1f;流程图是一种图形化表示流程的图表&#xff0c;通常用于描述业务、计划或工作流程。它可以帮助人们更好地理解复杂的流程&#xff0c;并且提供了一种清晰的方法来记录和共享流程信息。下面介绍一些绘制流程图的方法&#xff0c;可以帮助我们快速…

4 自动微分 Automatic Differentitaion

计算图 Computational Graph 图上的每个节点代表一个中间值边事输入输出的关系 forward 求导 forward mode AD 上图中从前向后&#xff0c;一步一步计算每个中间值对 x1的偏导&#xff0c;那么计算到 v7&#xff0c;就得到了整个函数对于 x1的偏导。 有limitation 对一个参数…

echarts开发遇到的问题

echarts开发遇到的问题 1.rich富文本标签作为横向柱状图的刻度标签&#xff0c;其中带有icon。rich里不能写参数&#xff0c;只能写死&#xff1f;圆角设置无效&#xff1f; 解决办法&#xff1a; 自己写横向柱状图 散点图性能优化配置的临界点&#xff0c;最低优化数值必须…

超全整理,软件测试高频面试题(功能/接口/自动化测试-附答案)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 功能测试 1、双十…

LCD—STM32液晶显示(4.液晶控制代码讲解)

目录 STM32液晶控制代码讲解 液晶接口封装介绍 使用LCD的配置步骤 内存操作要使用volatile进行修饰 图形绘制实现 绘制矩形 重点补充 STM32液晶控制代码讲解 液晶接口封装介绍 指南者液晶接口原理图 左边DB00—DB15表示液晶屏的数据线引脚&#xff0c;分别对应STM32的F…

使用ppocr突然退出问题

本次使用conda装了一个cuda10.2版本的paddleocr&#xff0c;然后所有的环境检查没问题&#xff0c;使用paddle自带的检查代码&#xff0c;输出提醒paddle可以正常使用&#xff1a; >>> import paddle >>> paddle.utils.run_check() 输出结果提示安装正常 …

零编程经验也能打造精美微信展示小程序的秘诀揭秘

随着微信的普及和发展&#xff0c;微信展示小程序成为了许多企业展示自己形象的重要渠道。那么如何快速地搭建一个精美的微信展示小程序呢&#xff1f;下面就为大家详细介绍一下具体操作步骤。 首先&#xff0c;进入【乔拓云】平台后台。乔拓云是一款非常优秀的小程序开发平台&…