Меня интересуют побочные эффекты и потенциальные проблемы следующего шаблона:
CREATE PROCEDURE [Name]
AS
BEGIN
BEGIN TRANSACTION
BEGIN TRY
[...Perform work, call nested procedures...]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
END
Насколько я понимаю, этот шаблон звучит при использовании с одной процедурой - процедура либо выполнит все свои инструкции без ошибок, либо откатит все действия и сообщит об ошибке.
Однако, когда одна хранимая процедура вызывает другую хранимую процедуру для выполнения некоторой части работы (при том понимании, что меньшая процедура иногда называется сама по себе), я вижу проблему, связанную с откатами - информационное сообщение ( Уровень 16) выдается с сообщением The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
. Это я предполагаю, потому что откат в подпроцедуре всегда откатывает внешнюю транзакцию, а не только транзакцию, запущенную в подпроцедуре.
Я хочу, чтобы все было отброшено назад и прервано, если возникла какая-либо ошибка (и сообщение об ошибке было сообщено клиенту как ошибка SQL), я просто не уверен в всех побочных эффектах, которые возникают из внешних слоев, пытающихся откат транзакции, которая уже откатна. Возможно, проверка @@TRANCOUNT
перед выполнением отката на каждом уровне TRY CATCH?
Наконец, есть клиентский конец (Linq2SQL), у которого есть собственный уровень транзакции:
try
{
var context = new MyDataContext();
using (var transaction = new TransactionScope())
{
// Some Linq stuff
context.SubmitChanges();
context.MyStoredProcedure();
transactionComplete();
}
}
catch
{
// An error occured!
}
В случае, если хранимая процедура, "MySubProcedure", вызванная внутри MyStoredProcedure, вызывает ошибку, могу ли я быть уверен, что все, что было сделано ранее в MyStoredProcedure, будет отменено, все операции Linq, сделанные SubmitChanges, будут отброшены назад и наконец, что ошибка будет зарегистрирована? Или что мне нужно изменить в моем шаблоне, чтобы гарантировать, что вся операция является атомарной, при этом все еще позволяя использовать дочерние части отдельно (т.е. Подпроцедуры должны иметь одинаковую атомную защиту).