C# 异步等待[MySQL数据库]导致的死锁
我有下面的异步方法,可以删除记录并将其插入MySQL数据库C# 异步等待[MySQL数据库]导致的死锁,c#,mysql,multithreading,entity-framework,async-await,C#,Mysql,Multithreading,Entity Framework,Async Await,我有下面的异步方法,可以删除记录并将其插入MySQL数据库 public async Task<Res> myNewFunc(int id, IEnumerable<Sample> obs) { using (var t = DbConnection.GetTransaction()) { await DbConnection.DeleteMany<M1>().Where(x.Id == id).ExecuteAsy
public async Task<Res> myNewFunc(int id, IEnumerable<Sample> obs)
{
using (var t = DbConnection.GetTransaction())
{
await DbConnection.DeleteMany<M1>().Where(x.Id == id).ExecuteAsync();
foreach (var ob in obs)
{
await DbConnection.InsertAsync(ob);
}
t.Complete();
}
}
使用上述代码时,MySQL面临死锁问题 因为您没有在最后一个for循环中等待,所以它将为所有这些线程启动线程,并同时并行运行所有这些线程。如果你这里有很多数据,他们都会争夺同样的资源。在每种情况下都会创建事务,然后从表中删除多条记录。然而,这可能不是真正的根本问题。在所有ExecuteAsync调用中,都不执行.ConfigureAwait(false)。这意味着在运行每个语句之后,它将等待,直到可以在原始线程(在本例中为UI线程)上恢复其工作。我不知道在for循环之后你会做什么,但是这个线程可能永远不会释放,所以这些db调用都不会返回,你会遇到死锁 有两种方法可以尝试解决此问题:
一次只能处理一个。对于#2,您可能还需要执行#1。foreach的
foreach
看起来很奇怪;您正在迭代nums
,但未使用该值。您正在调用method()
,而没有等待它或存储任务以供以后等待。只有在锁的范围扩展到一半时,才会出现死锁。重要的是要积极地锁定你可能需要的任何资源,而不仅仅是那些你确定你将需要的资源。如果看不到SQL,就很难判断数据库端可能发生的情况。同意@Christopher的观点,您应该查看数据库并找到死锁的实际原因。我不熟悉MySql死锁的故障排除,但快速搜索表明,您可以找到导致问题的实际语句。因为foreach中没有等待,所以它将在所有迭代中运行,而不会停止/暂停/等待。这将导致X个“方法”调用背靠背激发。每个人都会立即调用myNewFunc并等待。然后调用DeleteMany并等待。但是对myNewFunc和DeleteMany的调用彼此都不知道,如果它们试图删除同一个表中的内容,就会出现死锁,正如您所看到的。这将通过触发器和在该删除中调用的其他表传播出去。如何使用t.commit()
而不是complete?
public async Task<T> method()
{
//...
//...
var response = await DAL.myNewFunc(id, obs);
}
foreach(var num in nums)
{
method();
}
foreach(var num in nums)
{
method().GetAwaiter().GetResult();
}