Npgsql 提供者是否支持 TransactionScope?
Does Npgsql provider has support for TransactionScope?
我正在尝试将 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配置中启用分布式事务,检查max_prepared_transactions参数postgres.conf 文件(记得重启你的服务器)。
编辑#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 语句时),我得到一个空引用异常,堆栈跟踪如下:
服务器堆栈跟踪:
在 Npgsql.NpgsqlConnector.Cleanup()
在 Npgsql.NpgsqlConnector.Break()
在 Npgsql.NpgsqlConnector.ReadSingleMessage(DataRowLoadingMode dataRowLoadingMode,布尔 returnNullForAsyncMessage)
在 Npgsql.NpgsqlConnector.ReadExpectingT
…………
它是随机发生的。
Npgsql 确实支持 TransactionScope 并且已经这样做了很长一段时间。但是,至少目前,为了让您的连接参与 TransactionScope,您必须:
- 在您的连接字符串中包含
Enlist=true
,或者
- 致电NpgsqlConnection.EnlistTransaction
看看 Npgsql unit tests 周围的一些例子。
我正在尝试将 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配置中启用分布式事务,检查max_prepared_transactions参数postgres.conf 文件(记得重启你的服务器)。
编辑#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 语句时),我得到一个空引用异常,堆栈跟踪如下: 服务器堆栈跟踪: 在 Npgsql.NpgsqlConnector.Cleanup() 在 Npgsql.NpgsqlConnector.Break() 在 Npgsql.NpgsqlConnector.ReadSingleMessage(DataRowLoadingMode dataRowLoadingMode,布尔 returnNullForAsyncMessage) 在 Npgsql.NpgsqlConnector.ReadExpectingT ………… 它是随机发生的。
Npgsql 确实支持 TransactionScope 并且已经这样做了很长一段时间。但是,至少目前,为了让您的连接参与 TransactionScope,您必须:
- 在您的连接字符串中包含
Enlist=true
,或者 - 致电NpgsqlConnection.EnlistTransaction
看看 Npgsql unit tests 周围的一些例子。