菜的像徐坤
排名
7
文章
192
粉丝
15
评论
16
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

net core 使用redis 分布式锁

1725人阅读 2024/3/20 13:40 总访问:961001 评论:0 收藏:0 手机
分类: redis

在电商项目中,必定会与订单打交道。订单中必定会涉及到扣库存,但是在高并发项目中,库存余量不能及时刷新,
导致库存扣除得不正确,1000个并发请求下来,扣除的库存只有几十个。如何解决此问题,那就得加锁了。
还有其他解决办法也能处理此问题,本文只分享一下redis 分布式锁解决此问题。


第一步添加一个redis的获取锁,与释放锁的方法。在获取锁时,如果未获取到锁,那么就会尝试重复获取,
直到获取倒锁后,才返回。当然在这步你可以加一个超时时间,例如最多尝试获取30秒,避免释放锁异常在此一直死循环。
释放锁时只有锁的拥有者才能释放锁,避免锁被其他线程释放了,这个分布式锁就没有意义了。


  1.  public class RedisDistributedLock
  2.  {
  3.      private readonly ConnectionMultiplexer _redis;
  4.      private readonly IDatabase _database;
  5.  
  6.      public RedisDistributedLock(ConnectionMultiplexer redis)
  7.      {
  8.          _redis = redis;
  9.          _database = redis.GetDatabase();
  10.      }
  11.  
  12.      public async Task<boolAcquireLockAsync(string lockKey, string value, TimeSpan lockTimeout)
  13.      {
  14.          var acquired = await _database.StringSetAsync(lockKey, value, lockTimeout, When.NotExists);
  15.          if (!acquired)
  16.          {
  17.              // 循环重试直到成功或超时
  18.              var startTime = DateTime.UtcNow;
  19.              while (true)
  20.              {
  21.                  Thread.Sleep(10); // 等待一段时间后再重试
  22.  
  23.                  if (await _database.StringSetAsync(lockKey, value, lockTimeout, When.NotExists))
  24.                  {
  25.                      acquired = true// 成功获取到锁
  26.                      break;
  27.                  }
  28.              }
  29.          }
  30.          return acquired;
  31.      }
  32.  
  33.      public async Task ReleaseLockAsync(string lockKey, string value)
  34.      {
  35.          //验证锁的拥有者才能释放锁
  36.          string currentValue = await _database.StringGetAsync(lockKey);
  37.          if (currentValue == value)
  38.          {
  39.              await _database.KeyDeleteAsync(lockKey);
  40.          }
  41.      }
  42.  }


订单扣库存场景


  1.  private readonly ConnectionMultiplexer _connectionMultiplexer;
  2.   //创建一个redis锁
  3.   private readonly RedisDistributedLock _lockHelper;
  4.   private readonly string _lockKey = "inventory_lock:OrderSubmit"// 锁的唯一标识
  5.   public OrdersService(IFreeSql freeSql, ICacheService cacheService, ConnectionMultiplexer connectionMultiplexer)
  6.   {
  7.       _freeSql = freeSql;
  8.       _cacheService = cacheService;
  9.       _connectionMultiplexer = connectionMultiplexer;
  10.       _lockHelper = new RedisDistributedLock(_connectionMultiplexer);
  11.   }
  12.  
  13.   public async Task<CreateOrdersResult> OrderSubmitAsync(CreateOrderModel arg)
  14.   {
  15.       var orderStatus = OrderStatus.Fail;
  16.       var message = string.Empty;
  17.       var lockValue = $"lock_{CodeHelper.CreateGuid()}";
  18.       const int maxRetries = 5;
  19.       TimeSpan retryDelay = TimeSpan.FromMilliseconds(100);
  20.       if (await _lockHelper.AcquireLockAsync(_lockKey, lockValue, TimeSpan.FromSeconds(10)))
  21.       {
  22.           try
  23.           {
  24.               var oldInventory = await _freeSql.Select<Commodity>().Where(a => a.Code == arg.CommodityCode).FirstAsync();
  25.               if (oldInventory.Inventory >= arg.OrderQuantity && oldInventory.Inventory > 0)
  26.               {
  27.                   var repo = _freeSql.GetRepository<Commodity>();
  28.                   oldInventory.Inventory = oldInventory.Inventory - arg.OrderQuantity;
  29.                   await repo.UpdateAsync(oldInventory);
  30.                   orderStatus = OrderStatus.Success;
  31.                   message = "下单成功";
  32.               }
  33.               else
  34.               {
  35.                   message = "下单失败,库存不足";
  36.               }
  37.           }
  38.           catch (Exception e)
  39.           {
  40.               message = "下单失败," + e.Message;
  41.           }
  42.           finally
  43.           {
  44.               // 无论成功还是失败,最后都要释放锁
  45.               await _lockHelper.ReleaseLockAsync(_lockKey, lockValue);
  46.           }
  47.       }
  48.  
  49.       var ordersRepo = _freeSql.GetRepository<Orders>();
  50.       await ordersRepo.InsertAsync(new Orders()
  51.       {
  52.           Code = CodeHelper.CreateOrdersCode(),
  53.           UserCode = arg.UserCode,
  54.           CommodityCode = arg.CommodityCode,
  55.           OrderTime = DateTime.Now,
  56.           OrderAmount = arg.OrderAmount,
  57.           OrderQuantity = arg.OrderQuantity,
  58.           OrderStatus = orderStatus
  59.       });
  60.       return new CreateOrdersResult()
  61.       {
  62.           Status = true,
  63.           Message = message
  64.       };
  65.  
  66.   }


评价

net core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

.net mvc分部页,.net core分部页

.net分部页的三种方式第一种:@Html.Partial(&quot;_分部页&quot;)第二种:@{ Html.RenderPartial(&quot;分部页&quot;);}...

StackExchange.redis操作redis(net core支持)

官方git开源地址https://github.com/StackExchange/StackExchange.Redis官方文档在docs里边都是官方的文档通过nuget命令下...

.net core 使用session

tip:net core 2.2后可以直接启用session了,不用在自己添加一次session依赖,本身就添加了使用nuget添加引用Microsoft.AspN...

通俗易懂,什么是.net?什么是.net Framework?什么是.net core?

朋友圈@蓝羽 看到一篇文章写的太详细太通俗了,搬过来细细看完,保证你对.NET有个新的认识理解原文地址:https://www.cnblo...

asp.net core2.0 依赖注入 AddTransient与AddScoped的区别

asp.net core主要提供了三种依赖注入的方式其中AddTransient与AddSingleton比较好区别AddTransient瞬时模式:每次都获取一...

.net core 使用 Kestrel

Kestrel介绍 Kestrel是一个基于libuv的跨平台web服务器 在.net core项目中就可以不一定要发布在iis下面了Kestrel体验可以使...

net core使用cookie

net core中可以使用传统的cookie也可以使用加密的cookieNET CORE中使用传统cookie设置:HttpContext.Response.Cookies.Appe...

net core项目结构简单分析

一:wwwrootwwwroot用于存放网站的静态资源,例如css,js,图片与相关的前端插件等lib主要是第三方的插件,例如微软默认引用...

net core使用EF之DB First

一.新建一个.net core的MVC项目新建好项目后,不能像以前一样直接在新建项中添加ef了,需要用命令在添加ef的依赖二.使用Nug...

.net core使用requestresponse下载文件下载excel等

使用request获取内容net core中request没有直接的索引方法,需要点里边的Query,或者formstringbase64=Request.Form[&quot;f...

iframe自适应高度与配合net core使用

去掉iframe边框frameborder=&quot;0&quot;去掉滚动条scrolling=&quot;no&quot;iframe 自适应高度如果内容是固定的,那么就...

net core启动报错Unable to configure HTTPS endpoint. No server certificate was specified

这是因为net core2.1默认使用的https,如果使用Kestrel web服务器的话没有安装证书就会报这个错其实仔细看他的错误提示,其...

net core使用url编码与解码操作

net core中暂时还没有以前asp.net与mvc中的server对象。获取url的编码与解码操作不能使用以前的server对象来获取。使用的是...

下载net core

官方下载地址:https://dotnet.microsoft.com/download 进来之后就可以看到最新的下载版本可以直接点击下载,也可以下载其...

net core使用依赖注入来装载EF的上下文对象

妹子情人节快乐~.net core中用了不少的依赖注入,官方文档中也推荐使用。这样使用依赖注入来管理ef对象,还是比较科学,比如...