前言
有不少业务场景下需要生成流水号,比较简单的情况是新建一个表,然后利用自增Id来实现。但这种实现弊端比较大,占用数据库资源,操作步骤也多。于是想到使用Redis更好,因为是基于内存操作的,速度快且具有原子性。
实现
新建项目RedisDemo

新建接口ISequenceNumberGenerator
using System.Threading.Tasks;namespace RedisDemo{public interface ISequenceNumberGenerator{Task<long> GenerateAsync(string key);Task<string> GenerateAsync(string key, int totalWidth);}}
通过Nuget引入类库StackExchange.Redis
新建实现类SequenceNumberGenerator
using Microsoft.Extensions.Configuration;using StackExchange.Redis;using System.Threading.Tasks;namespace RedisDemo{public class SequenceNumberGenerator : ISequenceNumberGenerator{protected ConnectionMultiplexer RedisConnection { get; }public SequenceNumberGenerator(IConfiguration configuration){RedisConnection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);}protected virtual IDatabase GetDatabase(){return RedisConnection.GetDatabase();}public async Task<long> GenerateAsync(string key){var db = GetDatabase();return await db.StringIncrementAsync(key);}public async Task<string> GenerateAsync(string key, int totalWidth){var incrementValue = await GenerateAsync(key);return incrementValue.ToString().PadLeft(totalWidth, '0');}}}
代码写完开始测试
新建xunit测试项目
将自带的类文件重命名为SequenceNumberGenerator_Test
using Microsoft.Extensions.Configuration;using RedisDemo;using System;using System.Collections.Generic;using System.Linq;using System.Threading;using System.Threading.Tasks;using Xunit;using Xunit.Abstractions;namespace RedisDemoTest{public class SequenceNumberGenerator_Test{private readonly ISequenceNumberGenerator _sequenceNumberGenerator;private readonly ITestOutputHelper _outputHelper;public SequenceNumberGenerator_Test(ITestOutputHelper outputHelper){IConfigurationBuilder builder = new ConfigurationBuilder();builder.AddInMemoryCollection(new Dictionary<string, string>{{ "Redis:Configuration","127.0.0.1:6379"},});IConfigurationRoot configurationRoot = builder.Build();_sequenceNumberGenerator = new SequenceNumberGenerator(configurationRoot);_outputHelper = outputHelper;}[Fact]public async Task Generate_Test(){string key = "orderNumber" + Guid.NewGuid();string number = await _sequenceNumberGenerator.GenerateAsync(key, 4);Assert.Equal("0001", number);}[Fact]public void Generate2_Test(){string key = "orderNumber" + Guid.NewGuid();Parallel.For(1, 1000, async _ =>{long number = await _sequenceNumberGenerator.GenerateAsync(key);_outputHelper.WriteLine("number:" + number);});}}}
运行测试

可以看到实现没有问题。
