Това е нашият шаблон (регистрирането на грешки е премахнато)
Това е предназначено да обработва
- Статията на Пол Рандал "Няма такова нещо като вложена транзакция в SQL Server"
- Грешка 266
- Задействане на връщания назад
Обяснения:
-
всички TXN започват и извършват/връщат назад трябва да бъдат сдвоени, така че
@@TRANCOUNT
е еднакъв при влизане и излизане -
несъответствия на
@@TRANCOUNT
причинява грешка 266, защото-
BEGIN TRAN
увеличава@@TRANCOUNT
-
COMMIT
намалява@@TRANCOUNT
-
ROLLBACK
връща@@TRANCOUNT
до нула
-
-
Не можете да намалявате
@@TRANCOUNT
за текущия обхват
Това е, което смятате, че е „вътрешната транзакция“ -
SET XACT_ABORT ON
потиска грешка 266, причинена от несъответстващ@@TRANCOUNT
И също така се справя с проблеми като този "Време за изчакване на транзакция на SQL Server" на dba.se -
Това позволява TXN от страна на клиента (като LINQ). Една съхранена процедура може да бъде част от разпределена или XA транзакция или просто такава, инициирана в клиентски код (да речем .net TransactionScope)
Употреба:
- Всеки съхранен процес трябва да отговаря на един и същ шаблон
Резюме
- Така че не създавайте повече TXN, отколкото са ви необходими
Кодът
CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE @starttrancount int
BEGIN TRY
SELECT @starttrancount = @@TRANCOUNT
IF @starttrancount = 0
BEGIN TRANSACTION
[...Perform work, call nested procedures...]
IF @starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND @starttrancount = 0
ROLLBACK TRANSACTION;
THROW;
--before SQL Server 2012 use
--RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO
Бележки:
-
Проверката за връщане всъщност е излишна поради
SET XACT_ABORT ON
. Въпреки това ме кара да се чувствам по-добре, изглежда странно без него и позволява ситуации, в които не го искате -
Ремус Русану има подобна обвивка който използва точки за запазване. Предпочитам извикване на атомна база данни и не използвам частични актуализации като тяхната статия