Объем транзакции завершается неудачно с BeginTransaction в Oracle: соединение уже является частью локальной или распределенной транзакции

Такое странное поведение при использовании OracleConnection с 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.

редактировать

Спасибо за ответы, я полагаю, я должен добавить некоторые изменения, чтобы прояснить мой вопрос.

Прежде всего, приведенный выше код является демонстрацией проблемы. Допустим, у меня есть две библиотеки DLL MyProject.Oracle.dll и MyProject2.MsSql.dll, и я хочу использовать методы внутри этих библиотек DLL, и они используют db.BeginTransaction(). Если бы эти dll использовали TransactionScope, моя внешняя транзакция не была бы проблемой. Распределенная транзакция будет обработана без каких-либо проблем. Но я не могу изменить код внутри DLL.

И почему db.BeginTransaction () работает для Sql Server, а не для Oracle?

5 ответов

Я ударил тот же вопрос в сочетании с NHibernate. Другие ответы указывают не смешивать TransactionScope и BeginTransaction. К сожалению, нет источников, чтобы поддержать это требование, где добавлено. Вот мое исследование: как указано в MSDN (поиск "mix") и в этом обсуждении, не следует смешивать обе концепции, даже для SQL-Server. Почему это работает для SQL-сервера, как для локальных, так и для распределенных транзакций, мне до сих пор не ясно.

Некоторые считают, что это глупый вопрос, но он имеет смысл, когда рассматривается в контексте NHibernate (см. Здесь, здесь и здесь).

TransactionScope и DbConnection.BeginTransaction являются двумя эксклюзивными способами управления транзакциями. Вы используете 1 из них.

В тот момент, когда вы вызываете OracleConnection.Open, соединение оракула включается в транзакцию окружения системы. Все, что вам нужно сделать, это вызвать TransactionScope.Complete(), если вы хотите зафиксировать транзакцию или не вызывать ее, и в этом случае системная транзакция откатывается. Если вы не хотите сразу подключаться к "Open", вы можете установить для атрибута строки подключения " enlist " значение "dynamic", а затем явно подключиться с помощью вызова " OracleConnection.EnlistTransaction ".

Причина, по которой это работает для SQL/Server, а не для Oracle, заключается в том, что SQL/Server поддерживает вложенные транзакции, а Oracle — нет.

Вы должны сделать еще немного чтения на TransactionScope

Прежде всего перечисление TransactionScopeOption

Требуется:

Транзакция требуется по объему. Он использует внешнюю транзакцию, если она уже существует. В противном случае он создает новую транзакцию перед входом в область действия. Это значение по умолчанию.

Таким образом, транзакция, если она недоступна, создается и автоматически связывается.

Окружающая транзакция - это транзакция, в которой выполняется ваш код. Вы можете получить ссылку на внешнюю транзакцию, вызвав статическое свойство Current класса Transaction.

Вы не должны использовать внутренний объект транзакции, TransactionScope создание уже делает это и Complete метод совершает, внутренний BeginTransaction а также Commit вызовы методов не нужны.

Как это работает, если вы идете по этому пути?

Другие вопросы по тегам