Объем транзакции завершается неудачно с 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
вызовы методов не нужны.
Как это работает, если вы идете по этому пути?