给出解决问题的想法,给出:
- EF Core 代码优先
- 微软 SQL 服务器
- 具有异步请求的 ASP.Net 服务器。
我有一个包含用户数据的数据库,我需要一次为所选用户更改数据库中的多个表,并且数据必须更新或不更改。在数据更改时,用户可以在不同的线程中请求它们(请求是异步的)。
问题如下:
现在,当数据更改时,对于每个特定用户,它都被使用lock(sync)
- 作为从两个并行请求同步的一种方式,例如,第一个请求写入数据库,第二个请求读取。
当我更新基础时,我需要在lock
对象下更新它,所以我不能使用SaveChangesAsync()
,因为它不能在 pconstruct 下使用lock
。另外,我不能没有锁定,因为我一次更新了许多表,因此,必须保证用户不会意外地请求部分新数据和部分旧数据。原则上一切正常,但是更新过程相当长,为了可靠性,它被包装在一个事务中,这意味着该服务的所有其他用户都无法使用数据库,因为更新发生在同步模式下. 例如,如果有 1000 个用户提出更新数据的请求,那么该服务在处理这些请求时甚至可能会挂起一个小时。如果您能建议一个可能的正常解决方案,我将不胜感激。
下面是一个示意图代码,说明了所描述的:
object sync = new object()
async Task MyMethod(MyDBContext context)
{
// переключили поток но это не делает погоды так как далее идут синхронные операции и база виснет намертво для всех обращений к ней
using transaction = await context.Database.BeginTransactionAsync();
lock(sync)
{
UpdateTb1(context);
UpdateTb2(context);
UpdateTb3(context);
transaction.Commit();
}
}
void UpdateTb1(context)
{
context.Tb1.Add(VeryLongData);
context.SaveChanges();
}
void UpdateTb2(context)
{
context.Tb2.Add(VeryLongData);
context.SaveChanges();
}
void UpdateTb3(context)
{
context.Tb3.Add(VeryLongData);
context.SaveChanges();
}
我再重复一遍,这只是一个说明问题的代码示例,问题出在解决方案的方法上,而不是在代码中,所以不要因为所附示例不可重现的事实而扔西红柿。我将不胜感激建议的解决方案。
一旦保存了第一条数据,事务就会锁定数据库,并且没有人可以访问它。
在实际代码中,它仍然被包裹在 中try-catch
,因此如果在数据保存操作过程中出现错误,它不会被注意到,并且事务会回滚数据库中的更改。
您可以使用异步阻塞代替
lock
,也可以在单独的线程上运行同步方法。在这种情况下,主线程不会在事务等待和执行时被阻塞,其他用户将可以使用该服务。
据我了解,您无法使用异步方法,因为
lock
,现在您可以解决该问题并摆脱Task.Run()
,这是我的建议。顺便说一句,注意什么
SemaphoreSlim
implements ,小心使用它,当不再需要它时IDisposable
小心调用它。Dispose()