#c# #.net #sql-server #transactionscope
#c# #.net #sql-сервер #transactionscope
Вопрос:
У меня есть хранимая процедура SQL Server, которая создает ТРАНЗАКЦИЮ, подобную этой:
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO Table1 ...
INSERT INTO Table2 ...
COMMIT
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK
END CATCH
Эта хранимая процедура будет вставлена в две отдельные таблицы. Если один из них завершится с ошибкой, он будет откатываться.
У меня также есть следующий .net-код, который создает область транзакции:
using( var scope = new TransactionScope() )
{
SqlCommand cmd1 = connection.CreateCommand();
SqlCommand cmd2 = connection.CreateCommand();
// ...
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
scope.Complete();
}
Что произойдет, если и моя хранимая процедура, и мой код создают транзакцию? Вызовет ли это проблемы / должна ли быть распределенная транзакция или это нормально, если я создаю только одно соединение с базой данных?
Ответ №1:
Если бы у вас не было веской причины, я бы выполнял транзакции только в одном или другом месте.
И если возможно, я бы хотел, чтобы это место было базой данных. Это сокращает количество обходов, упрощает тестирование, изолирует его от других компонентов системы, уменьшает площадь открытой поверхности базы данных и защищает целостность периметра базы данных, заставляя действия проходить через четко определенный интерфейс.
Ответ №2:
В этом сценарии, если одна из ваших хранимых процедур завершится с ошибкой, она будет откатываться с использованием внутренней транзакции. Ваш код будет считать, что он завершен, и зафиксирует распределенную транзакцию. Это то, что вы хотите, поскольку удаленная транзакция бессмысленна, поскольку каждая из них будет выполняться индивидуально.
Если вы хотите, чтобы оба выполнялись или ни один из них не выполнялся, удалите свою транзакцию из хранимой процедуры и просто используйте распределенную транзакцию.
Комментарии:
1. Хранимая процедура выдаст ошибку, а не проглотит ее. К сожалению, мой пример этого не показал.
2. @Dismissile — вы обнаруживаете ошибку и откатываете транзакцию. В вашем
CATCH
3. Я имел в виду, что мой пример не показывал мою ошибку RAISERROR, хотя мой реальный сценарий делает это.