我可以通过尝试在一个相同的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
。
答案 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类中实现了工作单元模式。