在使用OracleConnection和TransactionScope时出现这种奇怪的行为。 如果我尝试在事务范围中使用connection.BeginTransaction(),我会得到简单优雅的InvalidOperationException:Connection已经是本地或分布式事务的一部分。
这里有一些代码:
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?
答案 0 :(得分:3)
我和NHibernate一起讨论了同样的问题。 其他答案表明不混合TransactionScope和BeginTransaction。遗憾的是,没有任何消在这里我的研究: 如MSDN(搜索“mix”)和in this discussion所述,不应混合使用这两个概念,即使对于SQL-Server也不应该。为什么它似乎适用于本地和分布式事务的SQL-Server,我仍然不清楚。
有些人似乎认为这是一个愚蠢的问题,但在NHibernate的上下文中看到它是有意义的(参见here,here和here)。
答案 1 :(得分:1)
TransactionScope和DbConnection.BeginTransaction是两种独有的事务管理方式。你使用其中一个。
当您致电OracleConnection.Open时,oracle连接将在环境系统事务中登记。您需要做的就是调用TransactionScope.Complete(),如果您想提交事务或不调用它,在这种情况下系统事务将被回滚。 如果您不想立即登记“打开”,可以将“登记”连接字符串属性设置为“动态”,然后通过调用“OracleConnection.EnlistTransaction”显式登记
答案 2 :(得分:0)
您不应该使用内部Transaction对象,TransactionScope
创建已经执行它并且Complete
方法执行提交,内部BeginTransaction
和Commit
方法调用不是需要的。
如果按照这种方式工作怎么样?
答案 3 :(得分:0)
你应该在TransactionScope
<强>必需强>:
范围需要交易。它使用环境事务 如果一个已经存在。否则,它会在之前创建一个新事务 进入范围。这是默认值。
因此创建并自动关联交易(如果不可用)。
环境事务是代码执行的事务。您可以通过调用Transaction类的静态Current属性来获取对环境事务的引用。