Npgsql 4.x 对 System.Transactions.TransactionsScope 的支持不起作用?
Npgsql 4.x support for System.Transactions.TransactionsScope not working?
我们有一个基于 Web 的多层 eHealth 系统平台,该平台使用 class/object 层次结构。例如,一个"patient clinic visit"对象可能由多个诊断对象、多个用药对象、多个观察对象、化验对象等组成。使用 .NET System.Transactions.TransactionScope.
处理数据库事务
将数据持久化到数据库时,层次结构中的每个嵌套对象:
- 实例化一个 TransactionScope(使用默认事务
必需选项)
- 实例化一个 NpgsqlConnection 连接
- 有自己的 SQL 和
- 设置transactionsScope.Complete(),如果一切顺利的话
为简化起见,对象层次结构中的对象就像下面的代码示例一样:
void RootMethod()
{
using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
SomeMethod();
AnotherMethod();
scope.Complete();
}
}
void SomeMethod()
{
using(TransactionScope scope = new TransactionScope())
{
using(NpgsqlConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open()
/* Perform transactional work here */
scope.Complete();
}
}
}
void AnotherMethod()
{
using(TransactionScope scope = new TransactionScope())
{
using(NpgsqlConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open()
/* Perform transactional work here */
scope.Complete();
}
}
}
封装在 "using(TransactionScope scope = new TransactionScope()) {...}" 代码块中的程序代码在 Oracle 上(使用 db Oracle 驱动程序)被纳入同一事务中,但在 Postgres 上使用 Npgsql 单独的事务似乎得到生成 而不是一笔交易。
因此,Postgres 上的事务因外键约束而失败 - 数据无法保存在子表中,因为创建的单独事务看不到在数据之前插入父表(在单独的事务中)的数据由父对象提交。
我们在 Npgsql connectString 中设置了 Enlist=true 并且服务器参数 max_prepared_transactions 在我们的 Postgres 服务器上设置为比 0 值更大的数字。
我们测试过的Npgsql驱动版本是4.0.7和4.1.2。我们开发环境中的 Postgres 服务器版本是版本 10.
Npgsql 文档 https://www.npgsql.org/doc/transactions.html 说 System.Transactions.TransactionScope 受支持(自 v3.3 以来一直如此),我们在 Whosebug 上搜索的其他 Npgsql 相关答案也是如此。
乍一看,Npgsql unit tests 似乎在事务单元测试中使用了一个数据库连接。
问题:
- Npgsql 是否支持多个 TransactionScope 和多个参与的数据库连接(根据 TransactionScope 实施指南(例如 https://docs.microsoft.com/en-us/dotnet/framework/data/transactions/implementing-an-implicit-transaction-using-transaction-scope)?
- 我们在这里遗漏了什么明显的东西吗?
如上所述,使用 Npgsql 4.x "using(TransactionScope scope = new TransactionScope()) {...}" 代码块中的每个打开的数据库连接似乎都会生成一个新事务,而不是在同一个事务中登记。
在内部 TransactionScope 中打开第二个 NpgsqlConnection 之前,需要关闭在外部 TransactionScope 中打开的 NpgsqlConnection(以允许 Npgsql 在内部重用相同的物理连接,而不会升级到分布式事务)。
我们有一个基于 Web 的多层 eHealth 系统平台,该平台使用 class/object 层次结构。例如,一个"patient clinic visit"对象可能由多个诊断对象、多个用药对象、多个观察对象、化验对象等组成。使用 .NET System.Transactions.TransactionScope.
处理数据库事务将数据持久化到数据库时,层次结构中的每个嵌套对象:
- 实例化一个 TransactionScope(使用默认事务 必需选项)
- 实例化一个 NpgsqlConnection 连接
- 有自己的 SQL 和
- 设置transactionsScope.Complete(),如果一切顺利的话
为简化起见,对象层次结构中的对象就像下面的代码示例一样:
void RootMethod()
{
using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
SomeMethod();
AnotherMethod();
scope.Complete();
}
}
void SomeMethod()
{
using(TransactionScope scope = new TransactionScope())
{
using(NpgsqlConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open()
/* Perform transactional work here */
scope.Complete();
}
}
}
void AnotherMethod()
{
using(TransactionScope scope = new TransactionScope())
{
using(NpgsqlConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open()
/* Perform transactional work here */
scope.Complete();
}
}
}
封装在 "using(TransactionScope scope = new TransactionScope()) {...}" 代码块中的程序代码在 Oracle 上(使用 db Oracle 驱动程序)被纳入同一事务中,但在 Postgres 上使用 Npgsql 单独的事务似乎得到生成 而不是一笔交易。
因此,Postgres 上的事务因外键约束而失败 - 数据无法保存在子表中,因为创建的单独事务看不到在数据之前插入父表(在单独的事务中)的数据由父对象提交。
我们在 Npgsql connectString 中设置了 Enlist=true 并且服务器参数 max_prepared_transactions 在我们的 Postgres 服务器上设置为比 0 值更大的数字。
我们测试过的Npgsql驱动版本是4.0.7和4.1.2。我们开发环境中的 Postgres 服务器版本是版本 10.
Npgsql 文档 https://www.npgsql.org/doc/transactions.html 说 System.Transactions.TransactionScope 受支持(自 v3.3 以来一直如此),我们在 Whosebug 上搜索的其他 Npgsql 相关答案也是如此。
乍一看,Npgsql unit tests 似乎在事务单元测试中使用了一个数据库连接。
问题:
- Npgsql 是否支持多个 TransactionScope 和多个参与的数据库连接(根据 TransactionScope 实施指南(例如 https://docs.microsoft.com/en-us/dotnet/framework/data/transactions/implementing-an-implicit-transaction-using-transaction-scope)?
- 我们在这里遗漏了什么明显的东西吗?
如上所述,使用 Npgsql 4.x "using(TransactionScope scope = new TransactionScope()) {...}" 代码块中的每个打开的数据库连接似乎都会生成一个新事务,而不是在同一个事务中登记。
在内部 TransactionScope 中打开第二个 NpgsqlConnection 之前,需要关闭在外部 TransactionScope 中打开的 NpgsqlConnection(以允许 Npgsql 在内部重用相同的物理连接,而不会升级到分布式事务)。