首页 > 解决方案 > 多个 Npsql 连接

问题描述

我正在尝试创建一个简单的服务器(.Net Core 5.0),它通过 Npgsql + Npgsql.EntityFramework 与 PostgreSQL DB(v 13.1)进行通信。

我有创建新用户、授予某些权限并检索 OID 的代码:

        string connString =
            String.Format(
                "Server={0};Username={1};Database={2};Port={3};Password={4};SSLMode=Prefer",
                PSqlHost, User, DBname, PSqlPort, Password);
        NpgsqlConnection psqlConnection = null;
        try
        {
            using (psqlConnection = new NpgsqlConnection(connString))
            {
                psqlConnection.Open();
                StringBuilder cmdBuilder = new StringBuilder();
                cmdBuilder.Append(string.Format("CREATE USER {0} WITH LOGIN PASSWORD '{1}';\r\n", signIn.Login, signIn.Pass));
                cmdBuilder.Append(string.Format("GRANT SELECT ON ALL TABLES IN SCHEMA public TO {0};\r\n", signIn.Login));
                cmdBuilder.Append(string.Format("GRANT SELECT, UPDATE ON ALL TABLES IN SCHEMA users TO {0};\r\n", signIn.Login));
                cmdBuilder.Append(string.Format("SELECT oid FROM pg_catalog.pg_authid WHERE rolname='{0}';\r\n", signIn.Login));
                using (var pgCmd = psqlConnection.CreateCommand())
                {
                    pgCmd.CommandText = cmdBuilder.ToString();
                    if (!pgCmd.IsPrepared) pgCmd.Prepare();
                    using (var reader = pgCmd.ExecuteReader())
                    {
                        if (!reader.HasRows) return TcpMessageSpec.Fail;
                        if (!reader.IsOnRow) reader.Read();
                        var oid = (uint)reader.GetValue(0);
                    }
                }
            }

            return TcpMessageSpec.OK;
        }
        catch (PostgresException ex)
        {
            Log.Exception(ex.MessageText);
            if (ex.SqlState == PostgresErrorCodes.InvalidPassword) return TcpMessageSpec.AuthFailed;
            else if (ex.SqlState == PostgresErrorCodes.DuplicateObject) return TcpMessageSpec.UserExists;
            return TcpMessageSpec.ConnectionFailed;
        }
        catch (Exception ex)
        {
            Log.Exception(ex.InnerException);
            return TcpMessageSpec.ConnectionFailed;
        }
        finally
        {

        }

这段代码在单个线程中完美运行,但我希望它在多个线程中运行。

当我从五个或更多线程运行此代码时,我会捕获PostgresException: "XX000: tuple concurrently updated". 但是,一些线程成功了(没有例外,OID 被检索)。

尝试解决(但结果相同):

  1. 我尝试过 NPSql 的异步版本
  2. 使用 NpgsqlConnection 事务
  3. 批处理/非批处理命令查询
  4. 我读过类似的问题

但是我仍然不明白我的错误在哪里。

标签: c#postgresqlmultithreadingnpgsql

解决方案


tuple concurrently updated是一个错误 PostgreSQL 有时会在某些 DDL 操作同时执行时返回(参见例如这个讨论)。这与 Npgsql 没有任何关系——您可能必须使用同步来确保这些 DDL 操作不会并行发生。


推荐阅读