【问题标题】:Transaction Scope fails with BeginTransaction in Oracle : Connection is already part of a local or a distributed transaction事务范围因 Oracle 中的 BeginTransaction 而失败:连接已经是本地或分布式事务的一部分
【发布时间】:2011-07-29 09:03:46
【问题描述】:

在使用带有 TransactionScope 的 OracleConnection 时出现这种奇怪的行为。 如果我尝试在事务范围内使用 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?

【问题讨论】:

    标签: c# oracle transactionscope odp.net


    【解决方案1】:

    我在使用 NHibernate 时遇到了同样的问题。 其他答案表明不要混合 TransactionScope 和 BeginTransaction。不幸的是,没有任何来源支持该声明的添加。这是我的研究: 正如MSDN(搜索“混合”)和in this discussion 中所述,不应将这两个概念混为一谈,甚至对于 SQL-Server 也不应。为什么它似乎适用于本地和分布式事务的 SQL-Server,我仍然不清楚。

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

    【讨论】:

    • 谢谢派珀..我也面临着类似的问题。您分享的链接真的很有帮助。
    【解决方案2】:

    TransactionScope 和 DbConnection.BeginTransaction 是事务管理的 2 种专有方式。您使用其中之一。

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

    【讨论】:

    • 我知道它们是不同的,我实际上编辑了一点,但我的问题仍然存在。为什么这适用于 Sql Server 而不适用于 Oracle?
    【解决方案3】:

    你应该多阅读TransactionScope

    首先枚举TransactionScopeOption

    必填

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

    因此,如果不可用的事务将被创建并自动关联。

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

    【讨论】:

      【解决方案4】:

      您不应该使用内部的 Transaction 对象,TransactionScope 创建已经这样做了,Complete 方法进行了提交,不需要内部的 BeginTransactionCommit 方法调用。

      如果你按照这种方式,它是如何工作的?

      【讨论】:

      • 这很好用(我已经编辑了一点问题)。但是为什么使用 BeginTransaction 和 Commit 适用于 Sqlserver 而不是 Oracle。
      猜你喜欢
      • 2015-02-10
      • 1970-01-01
      • 2012-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2023-03-29
      相关资源
      最近更新 更多