将TransactionScope与抛出OracleManagedDataAccess的System.PlatformNotSupportedException结合使用:“此平台不支持该操作。”

时间:2019-06-16 17:09:33

标签: c# oracle transactions transactionscope oracle-manageddataaccess

我可以通过尝试在一个相同的TransactionScope中打开2个连接(甚至在打开下一个之前关闭第一个连接)来成功地重现此内容,如下所示:

 var connectionString = "some connection";
 using (var t = new TransactionScope())
 {
    using (var con1 = new OracleConnection(connectionString))
    {
       con1.Open();
    }                    
    using (var con2 = new OracleConnection(connectionString))
    {
       con2.Open();//exception thrown at here
    }
 }  

实际上,我试图利用TransactionScope来为我的存储库实现某种类型的Ambient transaction(每个存储库都使用一个相同的连接字符串打开自己的连接)。上面的代码已尽可能简化,以帮助重现异常。

我不确定我做错了什么,或者TransactionScope至少在OracleManagedDataAccess中不支持.NET Standard。 我的项目针对.NET Standard 2.0(lib)和.NET Core(app)2.2,OracleManagedDataAccess是通过nuget(当然是针对.NET Standard)安装的,并且版本为2.19.3

这是上面发布的异常的堆栈跟踪:

  

在OracleInternal.MTS.MTSRMManager.CCPEnlistDistributedTxnToSysTxn(OracleConnectionImpl connImpl,Transaction txn,MTSTxnRM txnRM,MTSTxnBranch txnBranch)
  在OracleInternal.MTS.MTSRMManager.CCPEnlistTransaction(OracleConnectionImpl connImpl,Transaction transaction,MTSTxnRM txnRM,MTSTxnBranch txnBranch)
  在OracleInternal.ConnectionPool.PoolManager`3.GetEnlisted(ConnectionString csWithDiffOrNewPwd,布尔值bGetForApp,OracleConnection connRefForCriteria)
  在OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs,PM conPM,ConnectionString pmCS,SecureString securePassword,SecureString secureProxyPassword,OracleConnection connRefForCriteria)
  在Oracle.ManagedDataAccess.Client.OracleConnection.Open()

我觉得这是一个非常棘手的问题,这几乎取决于OracleManagedDataAccess。如果我不能使用TransactionScope,将没有简单的方法来实现Ambient transaction

1 个答案:

答案 0 :(得分:1)

TransactionScope 内部的单个连接应该可以正常工作。 当您争取到两个与 TransactionScope 的连接时,您正在尝试执行分布式事务,.NET Core不支持该事务:

  

从2.1版开始,.NET Core中的System.Transactions实现不包括对分布式事务的支持,因此您不能使用TransactionScope或CommittableTransaction来协调多个资源管理器之间的事务。

(摘自EF Core Using Transactions上的Microsoft文档文章)。

不支持分布式事务的原因是它们依赖于MSDTC,它特定于Windows。与作为跨平台框架的.NET Core路线图并不一致。

编辑:另一种方法

通常,应该更加谨慎地决定依赖分布式事务,因为这些事务很容易成为可伸缩性瓶颈。在现代体系结构中,通常不鼓励进行分布式事务。

在您的情况下,由于所有资源都是到同一个数据库的连接,因此您实际上不需要分布式事务。我建议实施(环境)Unit of Work

例如,您的应用程序中每个逻辑/业务操作可能都有一个工作单元实例。工作单元实例将缓冲所有请求的对数据库的修改(使用您自己的数据结构来表示修改)。在操作结束时,将确定工作单​​元。提交操作将包括:

  • 打开数据库连接和数据库事务
  • 使用单个数据库连接执行所有缓冲的修改
  • 提交数据库事务并关闭数据库连接

作为另一个示例,Entity Framework Core在DBContext类中实现了工作单元模式。