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


欢迎加群交流技术

在电商项目中,必定会与订单打交道。订单中必定会涉及到扣库存,但是在高并发项目中,库存余量不能及时刷新,
导致库存扣除得不正确,1000个并发请求下来,扣除的库存只有几十个。如何解决此问题,那就得加锁了。
还有其他解决办法也能处理此问题,本文只分享一下redis 分布式锁解决此问题。
第一步添加一个redis的获取锁,与释放锁的方法。在获取锁时,如果未获取到锁,那么就会尝试重复获取,
直到获取倒锁后,才返回。当然在这步你可以加一个超时时间,例如最多尝试获取30秒,避免释放锁异常在此一直死循环。
释放锁时只有锁的拥有者才能释放锁,避免锁被其他线程释放了,这个分布式锁就没有意义了。
- public class RedisDistributedLock
- {
- private readonly ConnectionMultiplexer _redis;
- private readonly IDatabase _database;
-
- public RedisDistributedLock(ConnectionMultiplexer redis)
- {
- _redis = redis;
- _database = redis.GetDatabase();
- }
-
- public async Task<bool> AcquireLockAsync(string lockKey, string value, TimeSpan lockTimeout)
- {
- var acquired = await _database.StringSetAsync(lockKey, value, lockTimeout, When.NotExists);
- if (!acquired)
- {
- // 循环重试直到成功或超时
- var startTime = DateTime.UtcNow;
- while (true)
- {
- Thread.Sleep(10); // 等待一段时间后再重试
-
- if (await _database.StringSetAsync(lockKey, value, lockTimeout, When.NotExists))
- {
- acquired = true; // 成功获取到锁
- break;
- }
- }
- }
- return acquired;
- }
-
- public async Task ReleaseLockAsync(string lockKey, string value)
- {
- //验证锁的拥有者才能释放锁
- string currentValue = await _database.StringGetAsync(lockKey);
- if (currentValue == value)
- {
- await _database.KeyDeleteAsync(lockKey);
- }
- }
- }
订单扣库存场景
- private readonly ConnectionMultiplexer _connectionMultiplexer;
- //创建一个redis锁
- private readonly RedisDistributedLock _lockHelper;
- private readonly string _lockKey = "inventory_lock:OrderSubmit"; // 锁的唯一标识
- public OrdersService(IFreeSql freeSql, ICacheService cacheService, ConnectionMultiplexer connectionMultiplexer)
- {
- _freeSql = freeSql;
- _cacheService = cacheService;
- _connectionMultiplexer = connectionMultiplexer;
- _lockHelper = new RedisDistributedLock(_connectionMultiplexer);
- }
-
- public async Task<CreateOrdersResult> OrderSubmitAsync(CreateOrderModel arg)
- {
- var orderStatus = OrderStatus.Fail;
- var message = string.Empty;
- var lockValue = $"lock_{CodeHelper.CreateGuid()}";
- const int maxRetries = 5;
- TimeSpan retryDelay = TimeSpan.FromMilliseconds(100);
- if (await _lockHelper.AcquireLockAsync(_lockKey, lockValue, TimeSpan.FromSeconds(10)))
- {
- try
- {
- var oldInventory = await _freeSql.Select<Commodity>().Where(a => a.Code == arg.CommodityCode).FirstAsync();
- if (oldInventory.Inventory >= arg.OrderQuantity && oldInventory.Inventory > 0)
- {
- var repo = _freeSql.GetRepository<Commodity>();
- oldInventory.Inventory = oldInventory.Inventory - arg.OrderQuantity;
- await repo.UpdateAsync(oldInventory);
- orderStatus = OrderStatus.Success;
- message = "下单成功";
- }
- else
- {
- message = "下单失败,库存不足";
- }
- }
- catch (Exception e)
- {
- message = "下单失败," + e.Message;
- }
- finally
- {
- // 无论成功还是失败,最后都要释放锁
- await _lockHelper.ReleaseLockAsync(_lockKey, lockValue);
- }
- }
-
- var ordersRepo = _freeSql.GetRepository<Orders>();
- await ordersRepo.InsertAsync(new Orders()
- {
- Code = CodeHelper.CreateOrdersCode(),
- UserCode = arg.UserCode,
- CommodityCode = arg.CommodityCode,
- OrderTime = DateTime.Now,
- OrderAmount = arg.OrderAmount,
- OrderQuantity = arg.OrderQuantity,
- OrderStatus = orderStatus
- });
- return new CreateOrdersResult()
- {
- Status = true,
- Message = message
- };
-
- }
评价