Я пытаюсь сделать быстрое фиктивное приложение, чтобы я мог изучить все тонкости System.Transactions. Это приложение взаимодействует с 2 различными базами данных SQLExpress. Если я получаю статистику транзакций в службах компонентов, я вижу транзакцию, запускаемую в externalScope, когда открывается второе соединение. Если значение failOuter равно true, транзакция прерывается, но не вызывает никаких исключений. Когда failInner имеет значение true, создается исключение TransactionAbortedException.
Из MSDN:
Когда ваше приложение завершает всю работу, которую оно хочет выполнить в транзакции, вы должны вызывать метод Complete только один раз, чтобы сообщить менеджеру транзакций о том, что транзакция приемлема для принятия. Это очень хорошая практика - помещать вызов Complete как последний оператор в блоке using.
Если этот метод не вызывается, транзакция прерывается, поскольку диспетчер транзакций интерпретирует это как системный сбой или эквивалент исключения, выданного в рамках транзакции.
Исключение TransactionAbortedException генерируется, если область создает транзакцию и транзакция отменяется.
Исходя из этого, я ожидаю, что мой externalScope сгенерирует исключение TransactionAbortedException, поскольку моя статистика транзакций показывает прерванную транзакцию каждый раз, когда я запускаю свое приложение, для которого failOuter имеет значение true. Мой метод возвращает true, так как никакие исключения не генерируются, даже если транзакция прерывается. Если я не прерву внутреннюю транзакцию, она будет вести себя так, как я ожидаю. Любое разъяснение будет наиболее ценно.
public bool CreateNestedTransaction(bool failOuter, bool failInner)
{
try
{
using (TransactionScope outerScope = new TransactionScope())
{
/* Perform transactional work here */
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
myCommand.ExecuteNonQuery();
}
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = Value";
myCommand.ExecuteNonQuery();
}
using (TransactionScope innerScope = new TransactionScope())
{
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test2"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
myCommand.ExecuteNonQuery();
}
if (failInner == false) { innerScope.Complete(); }
}
if (failOuter == false) { outerScope.Complete(); }
}
}
catch (TransactionAbortedException)
{
return false;
}
return true;
}