ADO.NET / Npgsql超时+准备好的事务

时间:2019-07-14 22:09:12

标签: ado.net npgsql transactionscope

在以下情况下需要一些澄清。 kubectl delete deployment -n metallb-system controller kubectl delete daemonset -n metallb-system speaker CanAddConcurrently失败。

DoesNotTimeout-(Npgsql.PostgresException:55000:已准备好的事务被禁用)。我了解这是因为我在postgres配置中禁用了此功能,但是为什么这会升级为准备好的事务?是因为它实际上得到了另一个NpgsqlConnection吗?如果是这样,这真的需要进行分布式交易吗?我可以使用knex运行相同的示例,使用具有相同池限制的node-postgres,在postgres中禁用准备好的事务,而在node.js下不会出现问题

CanAddConcurrently-(连接池已耗尽)我不明白为什么此处未重用池化连接。是否因为与测试中的顶级TransactionScope相关联而将其丢弃?即使在这种情况下,如果连接与同一事务相关联,为什么也不能重用该连接。我可以使用knex,具有相同池限制的node-postgres运行相同的测试用例,而在node.js下没有问题。

DoesNotTimeout
using Npgsql;
using System.Threading.Tasks;
using System.Transactions;

namespace TestCases
{
    public class Service
    {
        private readonly string connectionString;

        public Service(string connectionString)
        {
            this.connectionString = connectionString;
        }

        // I am aware this is only executing 1 query so does not have a need for an embedded transaction, this is just to keep example simple
        // removing the TransactionScope does not fix the issue, but for closer sample to original code it is here
        public async Task Add(string val)
        {
            using (var nestedScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            using (var conn = new NpgsqlConnection(this.connectionString))
            {
                await conn.OpenAsync();

                var cmd = new NpgsqlCommand("INSERT INTO data(value) values(@p);", conn);
                cmd.Parameters.AddWithValue("p", val);

                await cmd.ExecuteNonQueryAsync();

                nestedScope.Complete();
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您需要确切了解Task.WhenAll()(以及可能是异步的)的运行方式。

您的上述代码在相同的事务范围内同时{em {em} 十次,然后等待这10次调用完成。每次调用都会打开一个新的池连接,并尝试使用程序中存在的单个事务作用域。当一个事务作用域(即分布式事务)征集了多个连接时,这就是升级发生的原因。

在第二个示例中,这可能也解释了池耗尽的问题-这与不重新使用池连接有关,而是与您尝试同时使用太多 有关

您应该使用标准的foreach串行运行代码,仅在上一个操作完成后才执行下一个操作。可以同时运行多个操作-为了获得更好的性能-但您绝对不能在它们之间共享相同的事务范围。