多个 Npsql 连接

Multiple Npsql connections

我正在尝试创建一个简单的服务器 (.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. Batched/Not 批量命令查询
  4. 我看过类似的问题

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

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