Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步等待[MySQL数据库]导致的死锁_C#_Mysql_Multithreading_Entity Framework_Async Await - Fatal编程技术网

C# 异步等待[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

我有下面的异步方法,可以删除记录并将其插入MySQL数据库

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调用都不会返回,你会遇到死锁

有两种方法可以尝试解决此问题:

  • 每个Async()调用都必须是Async().ConfigureAwait(false)。如果确实是UI线程被锁定,这可能会修复它

  • 在最后一个for循环中,您需要等待每一个,因为可能数据库资源都被占用了。请改用此代码:


  • 一次只能处理一个。对于#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();
    }