事务范围因Oracle中的BeginTransaction而失败:Connection已经是本地或分布式事务的一部分

时间:2011-07-29 09:03:47

标签: c# oracle transactionscope odp.net

在使用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?

4 个答案:

答案 0 :(得分:3)

我和NHibernate一起讨论了同样的问题。 其他答案表明不混合TransactionScope和BeginTransaction。遗憾的是,没有任何消在这里我的研究: 如MSDN(搜索“mix”)和in this discussion所述,不应混合使用这两个概念,即使对于SQL-Server也不应该。为什么它似乎适用于本地和分布式事务的SQL-Server,我仍然不清楚。

有些人似乎认为这是一个愚蠢的问题,但在NHibernate的上下文中看到它是有意义的(参见hereherehere)。

答案 1 :(得分:1)

TransactionScope和DbConnection.BeginTransaction是两种独有的事务管理方式。你使用其中一个。

当您致电OracleConnection.Open时,oracle连接将在环境系统事务中登记。您需要做的就是调用TransactionScope.Complete(),如果您想提交事务或不调用它,在这种情况下系统事务将被回滚。 如果您不想立即登记“打开”,可以将“登记”连接字符串属性设置为“动态”,然后通过调用“OracleConnection.EnlistTransaction”显式登记

答案 2 :(得分:0)

您不应该使用内部Transaction对象,TransactionScope创建已经执行它并且Complete方法执行提交,内部BeginTransactionCommit方法调用不是需要的。

如果按照这种方式工作怎么样?

答案 3 :(得分:0)

你应该在TransactionScope

上做更多的阅读

首先列举TransactionScopeOption

<强>必需

  

范围需要交易。它使用环境事务   如果一个已经存在。否则,它会在之前创建一个新事务   进入范围。这是默认值。

因此创建并自动关联交易(如果不可用)。

环境事务是代码执行的事务。您可以通过调用Transaction类的静态Current属性来获取对环境事务的引用。