Рефакторинг ADO.NET - SqlTransaction против TransactionScope
Я "унаследовал" небольшой метод С#, который создает объект 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();
}
Что бы вы предпочли и почему?
Марк
Ответы
Ответ 1
Вы ничего не получите сразу, переключив свой существующий код на TransactionScope
. Вы должны использовать его для будущего развития из-за гибкости, которую он предоставляет. Это облегчит в будущем включение в транзакцию других событий, кроме вызовов ADO.NET.
Кстати, в вашем опубликованном примере экземпляры SqlCommand
должны быть в блоках using
.
Ответ 2
Корпорация Майкрософт рекомендует использовать область транзакций:
http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx
Основная идея заключается в том, что область транзакций будет управлять контекстом внешней транзакции для вас. Вы начинаете с разговора с одной базой данных, у вас есть транзакция sql, затем вы разговариваете с номером базы данных 2, а транзакция добавляется к распределенной транзакции.
Область транзакций работает для вас, так что вы можете сосредоточиться на функциональности системы, а не на сантехнике.
ИЗМЕНИТЬ
При использовании области транзакции все в пределах этой области охвачено транзакцией. Поэтому вы сохраняете строку кода, в которой вы связываете команду с транзакцией. Это возможный источник ошибок, например, если в 1000 был один шанс, что эта линия была забыта, сколько бы вы не пропали без вести.
РЕДАКТИРОВАТЬ 2
Согласен с комментарием Триинко ниже. Однако мы используем Entity Framework, EF автоматически закрывает и снова открывает соединение, чтобы заручиться его в транзакции. Он физически не закрывает соединение больше, он выпускает его в пул соединений и получает новый, который может быть одним и тем же или может быть другим.
Ответ 3
Я предпочитаю TransactionScope. Это не работает отлично в каждом сценарии, но в том, что вы описываете, это лучшее решение.
Мое рассуждение:
- Зачисление в транзакцию выполняется автоматически
- Откат транзакции в случае исключения является автоматическим
Вместе результат - это немного меньше кода и, как правило, более надежный дизайн, поскольку система обрабатывает некоторые детали для меня; это еще одна вещь, которую я должен помнить.
Кроме того, прозрачная регистрация транзакций может быть особенно полезна, когда у вас есть несколько вложенных методов в вашем DAL - хотя вам нужно позаботиться о том, чтобы ваша транзакция случайно не превратилась в распределенную, которая требует кода DTC, который может случиться, если вы используете несколько SqlConnections, даже если они указывают на один и тот же БД.
Ответ 4
Просто обратите внимание, что с помощью области транзакций иногда возникает большая проблема, потому что многие настройки, которые мы должны делать на сервере, такие как установка DTC, брандмауэра и т.д. Поэтому я рекомендовал использовать SqlTransaction, более сэкономить на реализации.
Ответ 5
Хорошо, может быть, слишком поздно для этого... но, во всяком случае, я запишу это для тех, кого это интересует...
Так как у меня есть лучшая картина сейчас, после большого количества трудностей с моим текущим подходом SqlTransaction
, который я мог бы изменить в пользу TransactionScope
, как я вижу... главное преимущество TransactionScope
что можно легко использовать в бизнес-слое.
Ответ 6
Также поздно... Вы можете легко иметь "вложенные" транзакции на бизнес-уровне, даже если база данных не поддерживает вложенные транзакции..NET управляет вложением и заканчивается использованием одной транзакции базы данных (по крайней мере, в случае SQL Server 2008+). Это значительно упрощает повторное использование кода доступа к данным за пределами его первоначального намерения как части более крупной транзакции.