使用了nuget包包括了:CSRedisCore,StackExchange.Redis,MyStack.DistributedLocking,Microsoft.Extensions.Configuration
安裝Redis並註冊為windows服務 直接參考這位兄弟的成果:
https://www.cnblogs.com/qingheshiguang/p/17952623
註冊服務:
配置檔案appsetting.json中加上Redis的連線字串 "Redis": "127.0.0.1:6379", Program.cs中新增註冊服務 // 新增併發鎖支援 builder.Services.AddDistributedLock(builder.Configuration["Redis"]);
using CSRedis; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Redis; using Utility.Concurrent; namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionExtensions { /// <summary> /// 新增併發鎖支援 /// </summary> /// <param name="services"></param> /// <param name="connectionString"></param> /// <returns></returns> public static IServiceCollection AddDistributedLock(this IServiceCollection services, string connectionString) { RedisHelper.Initialization(new CSRedisClient(connectionString)); services.AddSingleton<IDistributedCache>(new CSRedisCache(RedisHelper.Instance)); services.AddSingleton(typeof(IDistributedLock), typeof(DistributedLock)); return services; } } }
redis客戶端實現
using CSRedis; namespace Concurrent { public class DistributedLock : IDistributedLock { private const string _lockKey = "LockKey"; public async Task<bool> TryLockAsync(string key, int lockExpirySeconds = 10, long waitLockSeconds = 60) { if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException("鎖鍵值不能為空。"); } DateTime begin = DateTime.Now; while (true) { if (await RedisHelper.SetAsync($"{_lockKey}.{key}", Thread.CurrentThread.ManagedThreadId, lockExpirySeconds, RedisExistence.Nx)) { return true; } //不等待鎖則返回 if (waitLockSeconds == 0) { break; } //超過等待時間,則不再等待 if ((DateTime.Now - begin).TotalSeconds >= waitLockSeconds) { break; } Thread.Sleep(100); } return false; } public async Task UnLockAsync(string key) { await RedisHelper.DelAsync($"{_lockKey}.{key}"); } public async Task<T> LockExecuteAsync<T>(string key, Func<Task<T>> handle, int lockExpirySeconds = 10, long waitLockSeconds = 60) { if (await TryLockAsync(key, lockExpirySeconds, waitLockSeconds)) { try { return await handle?.Invoke(); } finally { try { await UnLockAsync(key); } finally { } } } return await Task.FromResult(default(T)); } } }
//鎖定分配的目標庫位 var hasLock = await _distributedLock.TryLockAsync(LocationCode, 5, 10); if (!hasLock) { throw new BizException(_Localizer["操作頻繁,稍後再試"]); }
業務中呼叫