ASP.NET Core 3.1 DbContext多线程操作异常问题求助
问题根源
异常的核心原因是仓储类中_appDbContext被声明为static静态字段:
- 你的
TestRepo被配置为Scoped生命周期,意味着每个请求会创建一个新的仓储实例;但静态字段_appDbContext会在整个应用域中被所有仓储实例共享。 - DbContext本身不是线程安全的,当多个并发请求同时通过共享的DbContext实例执行数据库操作时,就会触发"同一上下文上的前一个操作未完成就启动了第二个操作"的异常。
解决方案
1. 移除DbContext字段的static修饰符
修改TestRepo的代码,把静态字段改成实例字段,确保每个仓储实例持有独立的DbContext实例:
public class TestRepo : ITestRepo { // 移除static修饰符,添加readonly保证不可变 private readonly AppDbContext _appDbContext; public TestRepo(AppDbContext appDbcontext) { _appDbContext = appDbcontext; } public dynamic UpdateData(string input1) => _appDbContext.TestTable.Where(e => e.TestName == input1).Select(e => e.TestId).FirstOrDefault(); }
2. (可选但推荐)使用异步数据库操作
Web API属于IO密集型场景,异步操作能提升并发处理能力,避免线程阻塞。修改仓储和控制器方法为异步版本:
仓储层修改
public class TestRepo : ITestRepo { private readonly AppDbContext _appDbContext; public TestRepo(AppDbContext appDbcontext) { _appDbContext = appDbcontext; } public async Task<dynamic> UpdateDataAsync(string input1) => await _appDbContext.TestTable.Where(e => e.TestName == input1).Select(e => e.TestId).FirstOrDefaultAsync(); }
控制器修改
[HttpGet("{input1}", Name = "TestMethod")] [ProducesResponseType(400)] [ProducesResponseType(500)] public async Task<dynamic> TestMethod(string input1) => await _testRepo.UpdateDataAsync(input1);
3. 确认DbContext生命周期配置
确保AddDbContext保持默认的Scoped生命周期(你的现有代码已符合要求,无需修改),绝对不要将DbContext注册为Singleton,否则会再次引发线程安全问题。
额外说明
- DbContext的设计初衷是短生命周期使用(通常对应一个请求的生命周期),每个请求使用独立的DbContext实例能避免线程安全问题,同时保证数据上下文的一致性。
- 你使用的EF Core 2.2.6版本虽然较旧,但本次问题是通用的线程安全问题,和版本无关。
内容的提问来源于stack exchange,提问作者santosh kumar patro
相关产品推荐
相关产品推荐

