我正在使用InMemoryCache,如下所示。我没有通过startup.cs进行配置。这里的问题是它在托管的docker映像中引发以下错误,而本地未遇到此错误。
[Error] ConnectionId:0 RequestPath:/BuildSpec/RetrieveFor RequestId:1:0, SpanId:|aaaaa-ccccccc., a-415ea81b37b05aaa4f3, ParentId: Controller.RetrieveFor (core.web) => Microsoft.EntityFrameworkCore.Query: An exception occurred while iterating over the results of a query for context type 'act.core.data.ActDbContext'.
System.InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
at Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()
但是我们将数据库上下文注入到构造函数中。粘贴以下我正在使用的代码段。
private static readonly MemoryCache _cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 10
});
private async Task<IQueryable<SoftwareComponent>> GetOrCreateSoftwareComponent()
{
const string key = "xyz";
if (!_cache.TryGetValue(key, out IQueryable<xyz> xyz))
{
softwareComponents = await Task.Run(() => _ctx.xyztable.AsNoTracking()
.Include(a => a.SoftwareComponentEnvironments).AsNoTracking());
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.High)
.SetSize(1)
.SetSlidingExpiration(TimeSpan.FromMinutes(30))
.SetAbsoluteExpiration(TimeSpan.FromMinutes(60));
_cache.Set(key, xyz, cacheEntryOptions);
}
return softwareComponents;
}
这里的问题是,我没有在这里得到错误。为什么是MySQL错误。 注意:如果我重新部署相同的代码,则有一天可以解决该问题。但是错误一次又一次地回来。
答案 0 :(得分:0)
您在此行遇到错误:
softwareComponents = await Task.Run(() => _ctx.xyztable.AsNoTracking()
.Include(a => a.SoftwareComponentEnvironments).AsNoTracking());
Task.Run
>将指定的工作排队以在ThreadPool上运行,并返回该工作的任务或任务句柄。
这意味着其中的委托将在单独的线程上运行。
因此,如果您请求其他一些缓存数据(甚至在第一个完成之前,甚至是相同的),则另一个线程将启动并使用相同的上下文。 EF中不允许这样做,因此会出现错误。
简单的解决方法是使用锁
private readonly object lockObject = new object();
private async Task<IQueryable<SoftwareComponent>> GetOrCreateSoftwareComponent()
{
const string key = "xyz";
lock (lockObject)
{
if (!_cache.TryGetValue(key, out IQueryable<xyz> xyz))
{
softwareComponents = await Task.Run(() => _ctx.xyztable.AsNoTracking()
.Include(a => a.SoftwareComponentEnvironments).AsNoTracking());
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.High)
.SetSize(1)
.SetSlidingExpiration(TimeSpan.FromMinutes(30))
.SetAbsoluteExpiration(TimeSpan.FromMinutes(60));
_cache.Set(key, xyz, cacheEntryOptions);
}
}
return softwareComponents;
}
您每次都可以提供一个新的上下文,但是如果没有某种同步,您可能会对相同的值进行多个查询。