【问题标题】:Does Npgsql provider has support for TransactionScope?Npgsql 提供程序是否支持 TransactionScope?
【发布时间】:2020-01-17 12:25:05
【问题描述】:

我正在尝试将 TransactionScope 与 Npgsql 提供程序一起使用。 我在一个老问题 (provider for PostgreSQL in .net with support for TransactionScope) 中发现 Npgsql 还不支持它。 现在,大约 5 年后,Npgsql 是否支持 TransactionScope? 我为自己做了一个测试,使用 Npgsql 3.0.3 并使用以下代码:

using (var scope = new TransactionScope())
{
    using(var connection = new Npgsql.NpgsqlConnection("server=localhost;user id=*****;password=*****database=test;CommandTimeout=0"))
    {
        connection.Open();

        var command = new NpgsqlCommand(@"insert into test.table1 values ('{10,20,30}', 2);");
        command.Connection = connection;
        var result = command.ExecuteNonQuery();

        // scope.Complete();  <-- Not committed
    }
}

谁能确认Npgsql不支持TransactionScope?

编辑 #1 在确认 Npgsql 对 TransactionScope 的支持后,我发现你需要确保在你的 PostgreSQL 配置中启用分布式事务,检查 postgres.conf 中的 max_prepared_transactions 参数/em> 文件(记得重启你的服务器)。

编辑 #2 我在我的服务器上启用了分布式事务,但现在使用带有 Npgsql 的 TransactionScope 时出现错误。 这是我的代码:

using (var sourceDbConnection = new NpgsqlConnection(SourceConnectionString))
using (var destinationDbConnection = new NpgsqlConnection(DestinationConnectionString))
using (var scope = new TransactionScope())
    {
        sourceDbConnection.Open();
        destinationDbConnection.Open();

        Logger.Info("Moving data for the {0} table.", TableName.ToUpper());
        var innerStopWatch = new Stopwatch();
        innerStopWatch.Start();

        foreach (var entity in entities)
        {
            var etlEntity = new EtlInfoItem
            {
                MigratedEntityId = category.RowId,
                ProjectId = category.ProjectId,
                ExecutionDatetime = DateTime.Now
            };

            // Insert into the destination database
            var isRowMigrated = InsertEntity(entity, DestinationSchema, destinationDbConnection);

            if (isRowMigrated)
            {
                // Update the ETL migration table
                InsertCompletedEtlMigrationEntity(etlEntity, EtlSchema, sourceDbConnection);
            }
            else
            {
                // Update the ETL migration table
                InsertFailedEtlMigrationEntity(etlEntity, EtlSchema, sourceDbConnection);
            }
        }

        Logger.Info("Data moved in {0} sec.", innerStopWatch.Elapsed);

        Logger.Info("Committing transaction to the source database");
                innerStopWatch.Restart();

        scope.Complete();

        innerStopWatch.Stop();
        Logger.Info("Transaction committed in {0} sec.", innerStopWatch.Elapsed);
    }

当 TransactionScope 退出作用域时(退出 using 语句时),我得到一个 Null 引用异常,并带有以下堆栈跟踪: 服务器堆栈跟踪: 在 Npgsql.NpgsqlConnector.Cleanup() 在 Npgsql.NpgsqlConnector.Break() 在 Npgsql.NpgsqlConnector.ReadSingleMessage(DataRowLoadingMode dataRowLoadingMode,布尔返回 NullForAsyncMessage) 在 Npgsql.NpgsqlConnector.ReadExpectingT ………… 它是随机发生的。

【问题讨论】:

  • 在我的测试中,这不需要非零的 max_prepared_transactions。我在连接字符串中使用Enlist=true 使其正常工作(将 refcursor 参数从一个命令传递到另一个命令),max_prepared_transactions 为零。

标签: npgsql


【解决方案1】:

Npgsql 确实支持 TransactionScope 并且已经支持了很长一段时间。但是,至少目前,为了让您的连接参与 TransactionScope,您必须:

  1. 在您的连接字符串中包含Enlist=true,或
  2. 调用 NpgsqlConnection.EnlistTransaction

看看Npgsql unit tests 周围的一些例子。

【讨论】:

  • 感谢您的帮助。现在我有另一个问题。您可以在我的帖子中的 Edit #2 部分找到描述。
  • 你能为此打开一个问题吗?
  • 对于新访客,这不再是必需的,因为它现在是默认值
猜你喜欢
  • 1970-01-01
  • 2021-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-03
  • 1970-01-01
相关资源
最近更新 更多