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

Blazor中DbContext并发操作错误排查:未完成操作重复执行问题

扫描功能DbContext线程冲突问题排查

开发扫描功能时,按键监听器触发执行函数时出现以下错误:

在之前的操作完成前,对该上下文实例启动了第二个操作。这通常是不同线程同时使用同一DbContext实例导致的。

已经尝试用await处理异步进程,但问题仍未解决,线程冲突依旧,错误具体发生在GetByBarcode(String barcode)方法处。不确定是否遗漏了await的使用,或是问题本身更复杂,可能对await的理解有误。

相关代码片段:

前端触发代码

<div @onkeydown="@KeyDown"
 tabindex="0"
 @ref="scanner">

后端逻辑代码

public async Task KeyDown(KeyboardEventArgs e)
{
    barcode += e.Key;
    await CheckBarcode();
}

private async Task CheckBarcode()
{
    testStuff = await stuffRepository.GetByBarcode(barcode);
    if(testStuff is null)
    {
    // 空逻辑
    }
    else
    {
        await stuffRepository.Update(testStuff, loginID);
        await LoadStuff();
        barcode = "";
    }
}

public async Task<StuffDTO> GetByBarcode(string barcode)
{
    var obj = await _db.StuffTable.FirstOrDefaultAsync(u => u.Barcode == barcode);
    if (obj != null)
    {
        return _mapper.Map<Stuff, StuffDTO>(obj);
    }
    return new StuffDTO();
}

问题原因与修复方案

核心原因

  1. DbContext非线程安全:如果stuffRepository或DbContext是单例生命周期,多个线程会共用同一个实例,触发操作冲突。
  2. 按键触发频率过高:扫描枪按键触发速度极快,前一次CheckBarcode还未执行完毕,下一次KeyDown又启动新操作,导致并发调用同一DbContext。

具体修复步骤

  1. 调整生命周期
    确保stuffRepository和DbContext使用Scoped生命周期(ASP.NET Core默认),让每个操作都获取独立实例,避免跨线程复用。

  2. 添加并发锁控制
    在CheckBarcode方法上加锁,确保同一时间只有一个操作执行:

    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
    
    private async Task CheckBarcode()
    {
        await _semaphore.WaitAsync();
        try
        {
            testStuff = await stuffRepository.GetByBarcode(barcode);
            if(testStuff is null)
            {
                // 空逻辑
            }
            else
            {
                await stuffRepository.Update(testStuff, loginID);
                await LoadStuff();
                barcode = "";
            }
        }
        finally
        {
            _semaphore.Release();
        }
    }
    
  3. 优化条码输入逻辑
    扫描枪通常会在条码末尾发送Enter键,建议只在检测到Enter时才执行校验,减少不必要的并发:

    public async Task KeyDown(KeyboardEventArgs e)
    {
        if (e.Key == "Enter")
        {
            await CheckBarcode();
            barcode = "";
        }
        else
        {
            barcode += e.Key;
        }
    }
    
  4. 验证异步操作正确性
    确认所有DbContext相关操作都使用异步方法并正确await,避免同步阻塞导致的线程切换问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:02:06