TransactionScope. Основной провайдер не удалось выполнить команду EnlistTransaction. MSDTC прерывается
У нашей команды есть проблема, которая проявляется как:
Недопустимый базовый провайдер в EnlistTransaction; Не удается получить доступ к Объект object.Object: 'Transaction'.
![enter image description here]()
который, казалось, появился, как только мы начали использовать TransactionScope для обработки транзакций наших приложений.
Верхняя часть stacktrace фиксируется как:
в System.Data.EntityClient.EntityConnection.EnlistTransaction(транзакция Transaction) в System.Data.Objects.ObjectContext.EnsureConnection() в System.Data.Objects.ObjectContext.ExecuteStoreCommand(String CommandText, Object [] Параметры) в Reconciliation.Models.BillLines.BillLines.Reconciliation.Interfaces.IBillLineEntities.ExecuteStoreCommand(String, Object []) в Reconciliation.Models.Legacy.EntityDbEnvironment.ExecuteOracleSql(String SQL) в EntityDbEnvironment.cs: строка 41
В то же время обновляется журнал MSDTC, который я извлек с помощью здесь:
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:30.269 ;seq=136 ;eventid=TRANSACTION_BEGUN ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"transaction has begun, description :'<NULL>'"
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:30.269 ;seq=137 ;eventid=RM_ENLISTED_IN_TRANSACTION ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"resource manager #1002 enlisted as transaction enlistment #1. RM guid = 'defc4277-47a6-4cd9-b092-93a668e2097b'"
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=138 ;eventid=RECEIVED_ABORT_REQUEST_FROM_BEGINNER ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"received request to abort the transaction from beginner"
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=139 ;eventid=TRANSACTION_ABORTING ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"transaction is aborting"
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=140 ;eventid=RM_ISSUED_ABORT ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"abort request issued to resource manager #1002 for transaction enlistment #1"
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=141 ;eventid=RM_ACKNOWLEDGED_ABORT ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"received acknowledgement of abort request from the resource manager #1002 for transaction enlistment #1"
pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=142 ;eventid=TRANSACTION_ABORTED ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"transaction has been aborted"
Как вы видите RECEIVED_ABORT_REQUEST_FROM_BEGINNER секунду после регистрации RM_ENLISTED_IN_TRANSACTION.
Мы не можем понять, откуда этот запрос прерывания, или почему он был поднят. SQL, вызывающий проблему, - это простой SELECT, который мы можем выполнить без проблем через наш клиент базы данных.
Приложение работает большую часть времени, только изредка отображая эту проблему.
Мы используем Oracle 10.2.0.5.0 с Entity Framework.
UPDATE
Следуя советам @Astrotrain, я установил регистрацию в System.Transactions. Полученная окончательная запись буквально отрезана на полпути, хотя:
....
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Information">
<TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionScopeCreated</TraceIdentifier>
<Description>TransactionScope Created</Description>
<AppDomain>BillLineGeneratorUI.exe</AppDomain>
<ExtendedData xmlns="http://schemas.microsoft.com/2004/03/Transactions/TransactionScopeCreatedTraceRecord">
<TraceSource>[Base]
Как вы видите, исключение фактически предотвращает завершение журнала. Что я могу узнать из этого? Любые идеи?
Ответы
Ответ 1
Вместо использования средства отслеживания MSDTC (которое я нахожу ужасно спартанским), я могу рекомендовать использовать источник трассировки System.Transactions - просто включите следующее в свой web.config:
Если вы откроете файлы журнала с помощью SvcTraceViewer.exe
, вы получите красивое визуальное представление шагов.
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Transactions" switchValue="Information">
<listeners>
<add name="tx"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\MyApp-transactions-log.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
Не решение как таковое, но это может дать вам дополнительную информацию о том, что происходит не так.
Ответ 2
Как вы упомянули "Приложение работает большую часть времени, только изредка отображая эту проблему". этим мы можем заключить, что поставщик поддерживает распределенные транзакции, и причиной является некоторый другой прерывистый сбой в соединении или обработке.
-
Используете ли вы области вложенных транзакций, потому что если по какой-то причине внутренняя область откатывается (размещается без вызова завершена), которая немедленно откатывает внешнюю транзакцию, вызывающую ошибку. Используйте TransactionScopeOption.Required(RequiresNew также будет делать, но RequiresNew имеет другие связанные с ним проблемы, связанные с ним, поэтому лучше использовать Required) для решения этой проблемы.
-
В противном случае это может быть из-за какой-либо другой операции, когда транзакция активна и для решения в этом случае используется IsolationLevel = IsolationLevel.ReadCommitted.
Ответ 3
У нас тоже была эта проблема. Лучший способ решить эту проблему, похоже, открывает новое соединение с базой данных и просто выполняет необходимые транзакции. Держать транзакции как можно меньше всегда хорошо.
DatabaseContext db1 = new DatabaseContext();
doSomeDatabaseActions(db1);
TransactionOptions transOpts = new TransactionOptions();
transOpts.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transOpts))
{
using (DatabaseContext db2 = new DatabaseContext())
{
doDatabaseChecksWithLock(db2);
doChanges(db2);
db2.SaveChanges();
}
scope.Complete();
}
У нас была проблема без введения второго соединения. Обратите внимание, что ошибка также исчезла с использованием 1 соединения (db1), если транзакция была увеличена (сделана doSomeDatabaseActions часть транзакции).
Ответ 4
Это может быть комментарий, но он слишком большой. Надеюсь, это поможет.
Одна из самых типичных ошибок в вложенных транзакциях такова:
using(TransactionScope outerScope = new TransactionScope())
{
// Execute query 1
using(TransactionScope innerScope = new TransactionScope())
{
try
{
// Execute query 2
}
catch (Exception)
{
}
innerScope.Complete();
}
outerScope.Complete();
}
Теперь, если запрос 2, который находится внутри блока try/catch, выдает ошибку, вы поймаете исключение в блоке try/catch и обработаете его, но здесь supprise приложение будет вызывать ObjectDisposedException в строке 15, когда вы пытаетесь завершить транзакцию. Это связано с тем, что DTC уже поймал исключение, и, хотя вы его обработали, объекты TransactionScope, которые уже были удалены кодом .Net и транзакцией, были отброшены. Обратите внимание, что я сказал "объекты", это потому, что оба объекта TransactionScope были удалены, поскольку они являются частью одной и той же транзакции.