Рефакторинг ADO.NET -SqlTransaction против TransactionScope

я "унаследовал" небольшой метод C#, который создает ADO.NET объект SqlCommand и циклы над списком элементов, которые будут сохранены в базе данных (SQL Server 2005).

прямо сейчас используется традиционный подход SqlConnection/SqlCommand, и чтобы убедиться, что все работает, два шага (удалить старые записи, а затем вставить новые) обернуты в ADO.NET SqlTransaction.

using (SqlConnection _con = new SqlConnection(_connectionString))
{
   using (SqlTransaction _tran = _con.BeginTransaction())
   {
      try
      {
         SqlCommand _deleteOld = new SqlCommand(......., _con);
         _deleteOld.Transaction = _tran;
         _deleteOld.Parameters.AddWithValue("@ID", 5);

         _con.Open();

         _deleteOld.ExecuteNonQuery();

         SqlCommand _insertCmd = new SqlCommand(......, _con);
         _insertCmd.Transaction = _tran;

         // add parameters to _insertCmd

         foreach (Item item in listOfItem)
         {
            _insertCmd.ExecuteNonQuery();
         }

         _tran.Commit();
         _con.Close();
       }
       catch (Exception ex)
       {
          // log exception
          _tran.Rollback();
          throw;
       }
    }
}

теперь я много читал о классе .NET TransactionScope в последнее время, и Мне интересно, какой здесь предпочтительный подход? Получил бы я что-нибудь (читаемость, скорость, надежность), переключившись на использование

using (TransactionScope _scope = new TransactionScope())
{
  using (SqlConnection _con = new SqlConnection(_connectionString))
  {
    ....
  }

  _scope.Complete();
}

что вы предпочитаете, и почему?

Марк

6 ответов


вы сразу ничего не получите, переключив существующий код на использование TransactionScope. Вы должны использовать его для будущего развития из-за гибкости, которую он обеспечивает. Это облегчит в будущем включение вещей, отличных от ADO.NET вызывает транзакцию.

кстати, в вашем размещены, например,SqlCommand экземпляры должны быть в using блоки.


Я предпочитаю TransactionScope. Это не работает идеально в каждом сценарии, но в том, который вы описываете, это лучшее решение.

мои рассуждения:

  1. зачисление в транзакцию происходит автоматически
  2. откат транзакции в случае исключения происходит автоматически

вместе результат немного меньше кода и в целом более надежный дизайн, так как система обрабатывает некоторые детали для меня; это на одну вещь меньше Я должен помнить об этом.

кроме того, прозрачная Регистрация транзакций может быть особенно полезна, когда у вас есть несколько вложенных методов в вашем DAL-хотя вам нужно позаботиться о том, чтобы случайно ваша транзакция не превратилась в распределенную, которая требует DTC, что может произойти, если вы используете несколько SqlConnections, даже если они указывают на одну и ту же БД.


Microsoft рекомендует использовать область транзакций:

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

основная идея заключается в том, что область транзакции будет управлять "окружающим контекстом транзакции" для вас. Вы начинаете с разговора с одной базой данных, у вас есть транзакция sql, затем вы говорите с базой данных № 2, и транзакция повышается до распределенной транзакции.

объем транзакций работает вы, чтобы вы могли сосредоточиться на функциональности системы, а не на сантехнике.

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

при использовании области транзакции все, что находится в этой области, покрывается транзакцией. Поэтому необходимо сохранить строку кода, в которой команда подключается к транзакции. Это возможный источник ошибки, например, если бы был один шанс из 1000, что эта строка была забыта, сколько бы вы пропустили.

EDIT 2

согласен с комментарием по Трийнко ниже. Однако мы используем Entity Framework, EF автоматически закроет и снова откроет соединение, чтобы включить его в транзакцию. Он физически не закрывает соединение больше, он выпускает его в пул соединений и получает новый, который может быть тем же самым или может быть другим.


просто обратите внимание, используя область транзакций иногда мы будем много проблем, потому что многие настройки, которые мы должны сделать на сервере, как установка DTC, Брандмауэр и т.д. Поэтому я рекомендовал использовать SqlTransaction больше сохранить в реализации.


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

Так как у меня теперь есть лучшая картина, после того, как у меня было много трудностей с моим текущим SqlTransaction подход, который я мог бы измениться в пользу TransactionScope, Как я вижу... главное преимущество TransactionScope это его можно использовать очень легко в бизнес-слое.


поздно... Вы можете легко иметь "вложенные" транзакции на бизнес-уровне, даже если база данных не поддерживает вложенные транзакции. .NET управляет вложенностью и в конечном итоге использует одну транзакцию базы данных (по крайней мере, в случае SQL Server 2008+). Это значительно упрощает повторное использование кода доступа к данным вне его первоначального назначения в рамках более крупной транзакции.