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

并行加载下拉列表时DbContext上下文线程冲突问题排查

问题根源分析

你遇到的错误本质上是EF Core的核心限制:DbContext实例不是线程安全的,同一时间只能有一个操作在上面执行。虽然你把DbContext设为了Transient生命周期,但你的UnitOfWork模式导致所有仓储共享同一个DbContext实例——当你在LoadProposalsInterfaceDropdownList里并行调用多个仓储的方法时,所有任务都在操作同一个DbContext,这就触发了并发访问的错误。

为什么Transient没起作用?因为你的UnitOfWork实例(不管它的生命周期是Scoped还是其他)在构造时只会注入一次DbContext,之后所有仓储都复用这个实例,所以并行任务还是在同一个DbContext上跑,和DbContext的生命周期配置无关。

解决方案:为每个并行任务分配独立的DbContext

要解决这个问题,你需要让每个并行执行的仓储操作使用独立的DbContext实例。最合理的方式是利用IServiceScopeFactory创建独立的作用域,每个作用域内获取专属的仓储(和对应的DbContext)。

修改你的LoadProposalsInterfaceDropdownList方法,注入IServiceScopeFactory并重构代码:

public async Task<DropDownDataList> LoadProposalsInterfaceDropdownList(IServiceScopeFactory scopeFactory)
{
    var data = new DropDownDataList();

    // 为每个下拉列表任务创建独立的作用域,确保各自使用单独的DbContext
    var salesRepTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var salesRepRepo = scope.ServiceProvider.GetRequiredService<ISalesRepRepository>();
        return await salesRepRepo.GetDropDownListNoTracking();
    });

    var proposalStatusTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var statusRepo = scope.ServiceProvider.GetRequiredService<IProposalStatusRepository>();
        return await statusRepo.GetDropDownListNoTracking();
    });

    var sourceListTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var sourceRepo = scope.ServiceProvider.GetRequiredService<ISourceRepository>();
        return await sourceRepo.GetDropDownListNoTracking();
    });

    // 重复上述模式创建其他下拉列表的任务
    var yearOptionsTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var yearRepo = scope.ServiceProvider.GetRequiredService<IYearRepository>();
        return await yearRepo.GetDropDownListNoTracking();
    });

    var outForBidTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var bidRepo = scope.ServiceProvider.GetRequiredService<ICompBidsRepository>();
        return await bidRepo.GetDropDownListNoTracking();
    });

    var infoSecAwareTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var infoSecRepo = scope.ServiceProvider.GetRequiredService<IInfoSecAwareRepository>();
        return await infoSecRepo.GetDropDownListNoTracking();
    });

    var timeDriverTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var timeDriverRepo = scope.ServiceProvider.GetRequiredService<ITimeDriverRepository>();
        return await timeDriverRepo.GetDropDownListNoTracking();
    });

    var needsDriverTask = Task.Run(async () =>
    {
        using var scope = scopeFactory.CreateScope();
        var needsDriverRepo = scope.ServiceProvider.GetRequiredService<INeedsDriverRepository>();
        return await needsDriverRepo.GetDropDownListNoTracking();
    });

    // 等待所有任务完成
    await Task.WhenAll(
        salesRepTask, proposalStatusTask, sourceListTask, yearOptionsTask,
        outForBidTask, infoSecAwareTask, timeDriverTask, needsDriverTask);

    // 赋值结果
    data.SalesRepList = await salesRepTask as IReadOnlyList<DropDownList>;
    data.ProposalStatusList = await proposalStatusTask;
    data.SourceList = await sourceListTask;
    data.YearOptionsList = await yearOptionsTask;
    data.OutForBidList = await outForBidTask;
    data.InfoSecAwareList = await infoSecAwareTask;
    data.TimeDriverList = await timeDriverTask;
    data.NeedsDriverList = await needsDriverTask;

    return data;
}
额外优化建议
  1. 缓存下拉列表数据:下拉列表数据通常是不频繁变更的静态数据,你可以把这些数据缓存到内存(比如用IMemoryCache),第一次加载后直接读缓存,完全避免并行加载的需求,性能提升会更明显。

  2. 检查UnitOfWork的生命周期:确保你的UnitOfWork注册为Scoped生命周期(而不是Singleton),因为Singleton的UnitOfWork会持有DbContext实例很久,不仅有并发问题,还会导致数据过期。注册代码类似:

    builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
    
  3. 避免过度并行:如果数据库服务器资源有限,过多的并行查询反而可能导致性能下降,你可以根据实际情况调整并行任务的数量,或者使用Task.WhenAll但控制并发度。

内容的提问来源于stack exchange,提问作者John DK

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 14:57:40