事务作用域在Oracle中使用BeginTransaction失败:连接已经是本地或分布式事务的一部分
本文关键字:事务 一部分 分布式 Oracle 作用域 失败 BeginTransaction 连接 | 更新日期: 2023-09-27 18:03:49
在使用oraclecontion与TransactionScope时出现这种奇怪的行为。如果我尝试在事务范围内使用Connection . begintransaction(),我会得到简单优雅的InvalidOperationException:连接已经是本地或分布式事务的一部分。
下面是一些代码:var trxOptions = new TransactionOptions();
trxOptions.IsolationLevel = IsolationLevel.ReadCommitted;
using (var transaction = new TransactionScope(TransactionScopeOption.Required,trxOptions))
{
var c = ConfigurationManager.ConnectionStrings["oracle_test"].ConnectionString;
using (var oracle = new OracleConnection(c))
{
oracle.Open();
using (var tr = oracle.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
var cmd = oracle.CreateCommand();
cmd.CommandText = "INSERT INTO simple_user VALUES('a')";
cmd.ExecuteNonQuery();
tr.Commit();
}
}
// now go to sql server and insert data
transaction.Complete();
}
如果我不使用BeginTransaction一切工作。有什么可行的办法吗?
PS:我在Sql Server上没有这样的问题。
编辑
谢谢你的回答,我想我应该添加一些编辑使我的问题更清楚。首先,我上面提供的代码是对问题的演示。假设我有两个dll的MyProject.Oracle.dll和MyProject2.MsSql.dll,我想在这些dll中使用方法,他们使用db.BeginTransaction()。如果这些dll使用了TransactionScope,我的外部事务就不会有问题了。分布式事务处理没有任何问题。但是我不能更改dll中的代码。为什么db.BeginTransaction()适用于SqlServer而不适用于Oracle?
我在使用NHibernate时遇到了同样的问题。其他答案表明不要混合TransactionScope和BeginTransaction。不幸的是,没有任何来源支持这一说法。以下是我的研究:正如MSDN(搜索"mix")和本讨论中所述,不应该混合这两个概念,即使对于SQL-Server也是如此。为什么它似乎对SQL-Server工作,对于本地和分布式事务,我仍然不清楚。
有些人似乎认为这是一个愚蠢的问题,但它在NHibernate的上下文中是有意义的(见这里,这里和这里)。
TransactionScope和DbConnection。BeginTransaction是两种独立的事务管理方式。你可以用其中任意一个。
调用oracleconconnection的那一刻。打开时,oracle连接在环境系统事务中登记。然后你所需要做的就是调用TransactionScope.Complete(),如果你想提交事务或者不调用它,在这种情况下系统事务被回滚。如果你不想在'Open'上立即招募,你可以将'enlist'连接字符串属性设置为'dynamic',然后通过调用' oraclecconnection显式招募。EnlistTransaction '
它适用于SQL/Server而不是Oracle的原因是SQL/Server支持嵌套事务而Oracle不支持
你应该多读一些关于TransactionScope
首先是TransactionScopeOption
:
事务是范围所需要的。它使用环境事务如果已经存在的话。否则,它会创建一个新的事务进入作用域。这是默认值
如果事务不可用,则创建并自动关联。
环境事务是执行代码的事务。您可以通过调用transaction类的静态Current属性来获取对环境事务的引用。
你不应该使用内部Transaction对象,TransactionScope
创建已经做了,Complete
方法做了提交,不需要内部BeginTransaction
和Commit
方法调用。
如果你这样做,它是如何工作的?