From 4555ef2b378fbeb5d08dbc1164e1260ed65cb3d5 Mon Sep 17 00:00:00 2001 From: witskeeper Date: Sat, 3 Aug 2024 13:02:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B9=B6=E5=8F=91=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/content/concurrency/redis-lock.md | 67 +++++++++++++++++++ .../{domain => concurrency}/row-version.md | 0 docs/mkdocs.yml | 3 + 3 files changed, 70 insertions(+) create mode 100644 docs/content/concurrency/redis-lock.md rename docs/content/{domain => concurrency}/row-version.md (100%) diff --git a/docs/content/concurrency/redis-lock.md b/docs/content/concurrency/redis-lock.md new file mode 100644 index 00000000..56d670f2 --- /dev/null +++ b/docs/content/concurrency/redis-lock.md @@ -0,0 +1,67 @@ +# 悲观锁-Redis锁 + +## 什么是Redis锁? + +`Redis锁`是一种用于解决并发问题的机制,基于Redis的`悲观锁`实现。在并发环境中,多个用户可能同时变更同一资源,如果不加以限制,不同用户之间的操作可能相互覆盖,导致数据不一致的问题。`Redis锁`就是为了解决这个问题而设计的。 + +## Redis锁的实现原理 + +`Redis锁`的实现原理是通过在Redis中设置一个唯一的键来表示锁,当一个线程获取锁时,其他线程无法获取锁,直到该线程释放锁。具体步骤如下: +1. 线程A尝试获取锁,在Redis中设置一个唯一键,如果设置成功功,则获取锁。 +2. 线程A执行完操作后,删除该唯一键,释放锁。 +3. 线程B尝试获取锁,如果Redis中不存在该唯一键,则获取锁,否则等待或重试。 + +## Redis锁的使用场景 + +`Redis锁`主要用于解决高并发问题,例如在订单系统中,当多个用户同时下单时,可能会导致超卖的问题,此时可以使用`Redis锁`使得扣除库存的操作每次只能有一个线程执行,确保数据的一致性。 + +## 注册Redis锁 + +在Program.cs注册`IDistributedLock`: +```csharp +using NetCorePal.Extensions.DistributedLocks; +using NetCorePal.Extensions.DistributedLocks.Redis; +using StackExchange.Redis; + +var redis = ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("Redis")!); +builder.Services.AddSingleton(p => redis); +builder.Services.AddRedisLocks(); +``` + +## 使用Redis锁 + +在需要使用锁的地方注入`IDistributedLock`: +```csharp +using NetCorePal.Extensions.DistributedLocks; +namespace DistributedLocksSample +{ + public class RedisLockSample + { + private readonly IDistributedLock _lock; + public RedisLockSample(IDistributedLock @lock) + { + _lock = @lock; + } + + public async Task LockSample() + { + using (var l = await _lock.Acquire("lock-key", TimeSpan.FromSeconds(10))) + { + // do something + } + } + + public async Task TryLockSample() + { + var lockerHandler = await _lock.TryAcquire("lock-key", TimeSpan.FromSeconds(10))) + if (lockerHandler != null) + { + using (lockerHandler) + { + // do something + } + } + } + } +} +``` \ No newline at end of file diff --git a/docs/content/domain/row-version.md b/docs/content/concurrency/row-version.md similarity index 100% rename from docs/content/domain/row-version.md rename to docs/content/concurrency/row-version.md diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 2215af7f..2350e114 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -65,6 +65,9 @@ nav: - 上下文访问器: context/context-accessor.md - AspNetCore: context/aspnetcore-context-processor.md - CAP: context/cap-context-processor.md + - 并发控制: + - 乐观锁-行版本号: concurrency/row-version.md + - 悲观锁-Redis锁: concurrency/redis-lock.md - 多环境: - 环境上下文: env/env-context.md - 环境服务选择器: env/env-service-selector.md