C# Mysql - 在异步等待服务器的数据库查询上使用锁

C# Mysql - Using of locks on database query for async await server

我有 TcpListener class 并且我正在使用 async/await 阅读和写作。

对于这个服务器,我创建了一个数据库实例,我已经在其中准备了所有数据库查询。

但是对于不止一个 TcpClient 我不断收到异常:

An exception of type MySql.Data.MySqlClient.MySqlException occurred in MySql.Data.dll but was not handled in user code

Additional information: There is already an open DataReader associated with this Connection which must be closed first.

如果我理解正确的话,一次不能超过一个数据库查询,而超过一个 async 客户端就会出现问题。

所以我只是像这样在我的查询中添加了锁,一切似乎都很好。

   // One MySqlConnection instance for whole program.

   lock (thisLock)
   {
    var cmd = connection.CreateCommand();

    cmd.CommandText = "SELECT Count(*) FROM logins WHERE username = @user AND password = @pass";
    cmd.Parameters.AddWithValue("@user", username);
    cmd.Parameters.AddWithValue("@pass", password);

    var count = int.Parse(cmd.ExecuteScalar().ToString());
    return count > 0;
}

我也尝试过 usings 的方法,它为 SO 社区的某个人提到的每个查询创建新连接,但这种方法比锁慢得多:

    using (MySqlConnection connection = new MySqlConnection(connectionString))
    {
        connection.Open();   // This takes +- 35ms and makes worse performance than locks

        using (MySqlCommand cmd = connection.CreateCommand())
        {
            cmd.CommandText = "SELECT Count(*) FROM logins WHERE username = @user AND password = @pass";
            cmd.Parameters.AddWithValue("@user", username);
            cmd.Parameters.AddWithValue("@pass", password);

            int count = int.Parse(cmd.ExecuteScalar().ToString());
            return count > 0;
        }
    }

我使用 Stopwatch 对这种方法进行了基准测试,并且在 +- 20 毫秒内执行了一个带锁连接的查询,这只是网络延迟,但使用它是 +- 55 毫秒,因为 .Open() 方法花费 +- 35 毫秒。

如果性能更差,为什么很多人使用方法和 usings?还是我做错了什么?

没错,打开连接是一个耗时的操作。为了缓解这种情况,ADO.NET 有连接池。检查 this article 了解详情。

如果您继续进行性能测试并检查后续连接的计时,您应该会看到 connection.Open() 的时间有所改善并接近 0 毫秒,因为连接实际上是从池中获取的。

通过您的锁定实现,您实际上只使用了一个连接的连接池。虽然这种方法可以在简单的测试中表现出更好的性能,但在高负载的应用程序中会表现出非常差的结果。