是否生成多个数据库上下文生成死锁

本文关键字:上下文 死锁 数据库 是否 | 更新日期: 2023-09-27 18:32:34

总结我的代码,我有一个使用DbContextStrategy<E>IRepository<E>

DbContextStrategy<E>DbContext扩展,并使用DbSet<E>对数据库执行 LINQ 操作。

E只是泛型传递的实体类型。

在我的 Web API 控制器中,我使用此存储库接口来获取我的资源。

但是,某些实体依赖于其他实体。例如,在PUTPOST请求中,我应该验证输入外键以检查它们是否有效。

因此,我需要实例化一个新IRepository<X>其中X是外部实体类型。

为了使我的开发尽可能简单,我生成了一个基类层,它将为我处理配置、缓存、依赖关系注入和 HTTP 方法绑定。

在我的最小子控制器中,我有以下方法:

/// Base class provides me with the Season entity fetched from the database.
/// An IRepository<Season> is open in the background, and therefore, a DbContext too.
protected override Season UpdateEntity(Season entity, SeasonPostDTO dto)
{
     Task<bool> validatingShow = ValidateShow(dto.Show);
     entity.Number = dto.Number;
     entity.ReleaseDate = dto.ReleaseDate;
     entity.Image = dto.Image;
     entity.TVShowId = dto.Show;
     entity.BlameUserId = Convert.ToInt32(GetCurrentUserId());
     validatingShow.Wait();
     if (!validatingShow.Result)
          throw new EntityNotFoundException("Show not found");
     return entity;
} 

这是将处理实体更新的方法。基本控制器将调用它,然后调用将更新DbContext中的实体的repository.Edit(entity)。手术后,IRepository<Season>被处置。

ValidateShow 是一种私有方法,它只检查是否存在showId

private async Task<bool> ValidateShow(int id) {
     //This will instantiate a new IRepository<TVShow>, and therefore a new DbContext
     return await UseAsyncDependency<TVShow, bool>(async (showRepo) => {
         return (await showRepo.ReadAsync(id)) != null;
     });
}

但是,ValidateShow方法只是停留在无限循环中。我已经调试了该方法,并且调用被正确委托给DbSet<TVShow>并且循环发生在:context.Entities.FindAsync(keys)

该方法工作正常,因为我使用相同的ReadAsync方法来获取Season实体。

但是,当有两个不同的DbContext打开时,它似乎会产生某种僵局。( DbSet<Season>DbSet<TVShow> (

我应该指出,这两个DbContext都连接到同一个数据库。

异步/等待执行流从独立到数据库集

IRepository<E>IDao<E>上调用SelectAsync(keys)方法,在DbContextStrategy<E>上调用SelectAsync(keys)方法。

下面是代码跟踪:

默认存储库 : 独立:

public async Task<E> ReadAsync(params object[] keys) {
    if(keys == null || keys.Length < 1) return null;
    return await dao.SelectAsync(keys);
}

默认道:爱道

public async Task<E> SelectAsync(params object[] keys) {
    return await ForEachStrategyAsync(async (strategy) => {
        return await strategy.SelectAsync(keys);
    }, (entity) => {
        return entity != null;
    });
}
private async Task<R> ForEachStrategyAsync<R>(Func<IPersistenceStrategy<E>, Task<R>> function,
                                              Func<R, bool> assertion) {
    R lastResult = default(R);
    foreach(IPersistenceStrategy<E> strategy in strategies) {
         lastResult = await function(strategy);
         if(assertion(lastResult)) break;
    }
    return lastResult;
}

DbContextStrategy : IPersistenceStrategy

public async Task<E> SelectAsync(params object[] keys) {
    return await context.Entities.FindAsync(keys);
}

是否生成多个数据库上下文生成死锁

DbContext的每个实例都有自己的事务,这可能会导致死锁,但您需要一个写入操作才能发生这种情况,并且 DbContext 仅在您调用SaveChanges()时保存对数据库的更改,而您在调用之前不会调用validatingShow.Wait()

这个Wait()调用更有可能是一个问题。如果您使用的是 async/await,则实际上应该对整个调用堆栈(UpdateEntity()及以上,包括 Web API 控制器的方法(使用 async/await。

这里描述了发生这种情况的原因 http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html