You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求.NET Core API生成不重复9位唯一整数的高效方案

优化方案推荐

针对你的需求,推荐以下几个低开销、高并发友好的解决方案:

1. 数据库序列(Sequence)+ 内存预取

SQL Server的序列是专门生成唯一连续值的数据库对象,原子性强,且支持批量取值,能大幅减少数据库交互次数:

步骤:

  • 先在SQL Server创建序列:
CREATE SEQUENCE dbo.NineDigitSeq
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 999999999
    CYCLE OFF; -- 到达最大值后停止,避免重复
  • 在.NET Core中,维护一个内存队列(ConcurrentQueue<int>),初始化时从数据库批量获取一批值(比如100个);
  • 每次请求从队列取一个值,当队列剩余数量低于阈值(比如20)时,异步触发批量获取下一批值的操作;
  • 取值逻辑示例:
private readonly ConcurrentQueue<int> _idQueue = new ConcurrentQueue<int>();
private readonly object _fetchLock = new object();
private const int BatchSize = 100;
private const int Threshold = 20;

public async Task<int> GetNextIdAsync()
{
    if (_idQueue.TryDequeue(out var id))
    {
        // 检查队列剩余量,不足则异步补全
        if (_idQueue.Count <= Threshold)
        {
            Task.Run(FetchBatchAsync);
        }
        return id;
    }
    // 队列为空时同步获取一批
    await FetchBatchAsync();
    _idQueue.TryDequeue(out id);
    return id;
}

private async Task FetchBatchAsync()
{
    // 避免并发重复获取
    lock (_fetchLock)
    {
        if (_idQueue.Count > Threshold) return;
    }
    using var conn = new SqlConnection("YourConnectionString");
    await conn.OpenAsync();
    // 批量获取Sequence值
    var cmd = new SqlCommand($"SELECT NEXT VALUE FOR dbo.NineDigitSeq FROM (VALUES(1),{(string.Join(",", Enumerable.Range(2, BatchSize-1).Select(x => "(1)")))) AS T", conn);
    using var reader = await cmd.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        _idQueue.Enqueue(reader.GetInt32(0));
    }
}

这个方案的优势:大部分请求直接从内存取,数据库交互极少;序列是数据库原子操作,完全避免重复;支持多实例部署(多个API实例各自预取,数据库保证全局唯一)。

2. 单实例场景:Interlocked原子递增 + 异步持久化

如果你的API是单实例部署,用Interlocked类做内存原子递增,比lock开销小一个数量级,同时异步将最新值持久化到数据库(避免重启后丢失):

步骤:

  • 数据库建一张计数器表,只存一条记录:
CREATE TABLE dbo.IdCounter (
    Id INT PRIMARY KEY DEFAULT 1,
    CurrentValue INT NOT NULL DEFAULT 0
);
INSERT INTO dbo.IdCounter DEFAULT VALUES;
  • 启动时从数据库读取CurrentValue,初始化内存中的计数器;
  • 每次请求用Interlocked.Increment原子递增,然后异步更新数据库:
private int _currentId;
private readonly ILogger<YourService> _logger;

public async Task InitializeAsync()
{
    using var conn = new SqlConnection("YourConnectionString");
    await conn.OpenAsync();
    var cmd = new SqlCommand("SELECT CurrentValue FROM dbo.IdCounter", conn);
    _currentId = (int)await cmd.ExecuteScalarAsync();
}

public int GetNextId()
{
    var nextId = Interlocked.Increment(ref _currentId);
    // 异步更新数据库,不阻塞请求
    _ = UpdateDatabaseAsync(nextId);
    return nextId;
}

private async Task UpdateDatabaseAsync(int newValue)
{
    try
    {
        using var conn = new SqlConnection("YourConnectionString");
        await conn.OpenAsync();
        var cmd = new SqlCommand("UPDATE dbo.IdCounter SET CurrentValue = @NewValue WHERE Id = 1", conn);
        cmd.Parameters.AddWithValue("@NewValue", newValue);
        await cmd.ExecuteNonQueryAsync();
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Failed to update counter in database");
        // 可根据需求添加重试逻辑
    }
}

优势:内存操作无锁(CPU原子指令),性能极高;异步更新数据库不影响请求响应速度;仅适用于单实例,多实例会出现重复。

3. 多实例场景:内存缓存 + 数据库乐观锁

如果多实例部署但不想用序列,可结合内存缓存和乐观锁,平衡性能与一致性:

步骤:

  • 同样用上述的IdCounter表;
  • 每个实例内存存当前计数器值,每次请求先内存递增,然后尝试用乐观锁更新数据库;
  • 如果更新失败(说明其他实例已修改),则从数据库拉取最新值,重新递增:
private int _currentId;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

public async Task<int> GetNextIdAsync()
{
    var nextId = Interlocked.Increment(ref _currentId);
    try
    {
        await UpdateWithOptimisticLockAsync(nextId);
        return nextId;
    }
    catch (OptimisticLockException)
    {
        // 冲突时重新获取最新值
        await _semaphore.WaitAsync();
        try
        {
            using var conn = new SqlConnection("YourConnectionString");
            await conn.OpenAsync();
            var cmd = new SqlCommand("SELECT CurrentValue FROM dbo.IdCounter", conn);
            _currentId = (int)await cmd.ExecuteScalarAsync();
        }
        finally
        {
            _semaphore.Release();
        }
        // 重新递增
        return Interlocked.Increment(ref _currentId);
    }
}

private async Task UpdateWithOptimisticLockAsync(int newValue)
{
    using var conn = new SqlConnection("YourConnectionString");
    await conn.OpenAsync();
    var cmd = new SqlCommand("UPDATE dbo.IdCounter SET CurrentValue = @NewValue WHERE CurrentValue = @OldValue", conn);
    cmd.Parameters.AddWithValue("@NewValue", newValue);
    cmd.Parameters.AddWithValue("@OldValue", newValue - 1);
    var rowsAffected = await cmd.ExecuteNonQueryAsync();
    if (rowsAffected == 0)
    {
        throw new OptimisticLockException("Counter update conflict");
    }
}

// 自定义异常类
public class OptimisticLockException : Exception
{
    public OptimisticLockException(string message) : base(message) { }
}

优势:大部分请求内存操作完成,冲突时才触发数据库交互;支持多实例;性能略低于序列方案,但实现简单。


内容的提问来源于stack exchange,提问作者Farooq Awan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 05:45:40