DbContext并发操作异常求助:单元测试报错问题排查
解决DbContext并发操作异常问题
问题根源
DbContext实例不是线程安全的,你的Process方法通过Task.WhenAll同时执行Job1和Job2,两个任务共享同一个_myContext实例,并发执行数据库操作时就会触发该异常。
解决方案
修改MyServices,通过IDbContextFactory<MyContext>为每个Job创建独立的DbContext实例,避免共享实例导致的并发冲突。
步骤1:修改MyServices的依赖注入
将直接注入MyContext改为注入IDbContextFactory<MyContext>,并在每个Job内部创建独立上下文:
public class MyServices : IMyServices { private readonly IDbContextFactory<MyContext> _contextFactory; // 修正构造函数名称(原代码笔误为CallQEtlServices) public MyServices(IDbContextFactory<MyContext> contextFactory) { _contextFactory = contextFactory; } public async Task Process(CancellationToken cancellation) { await Task.WhenAll(Job1(cancellation), Job2(cancellation)); } public async Task Job1(CancellationToken cancellation) { // 为当前Job创建独立的DbContext实例,using自动释放资源 using var myContext = _contextFactory.CreateDbContext(); // 原有业务逻辑 myContext.RemoveRange(myContext.Students); await myContext.SaveChangesAsync(cancellation); await myContext.AddRangeAsync(Students, cancellation); var result = await myContext.SaveChangesAsync(cancellation); } // Job2执行同样的修改,使用独立的DbContext public async Task Job2(CancellationToken cancellation) { using var myContext = _contextFactory.CreateDbContext(); // Job2的业务逻辑(操作对应模型) // myContext.RemoveRange(...); // await myContext.SaveChangesAsync(cancellation); // ... } }
步骤2:确认DbContextFactory注册正确
你的Program.cs中已经正确注册了IDbContextFactory<MyContext>,无需修改:
builder.Services.AddDbContextFactory<MyContext>(options => options.UseSqlServer(myServicesConnStr), ServiceLifetime.Transient);
关键说明
IDbContextFactory专门用于在并发场景或需要多个上下文实例的场景中创建独立的DbContext,从根源避免线程安全问题。using语句会自动管理DbContext的生命周期,确保操作完成后及时释放资源。- 每个Job使用独立的DbContext实例,彻底避免同一实例被多个线程同时操作的情况。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

