I den här artikeln kommer vi att utforska SQL Server Nested Transactions, ett transaktionsblock med en eller flera transaktioner.
Bilden beskriver en enkel modell av den kapslade transaktionen.
Den inre transaktionen är en lagrad procedur som består av transaktionsblock. MSDN rekommenderar att "hålla transaktioner så korta som möjligt", vilket är helt tvärtemot den första metoden. Enligt min åsikt rekommenderar jag inte att använda kapslade transaktioner. Ändå måste vi ibland använda dem för att lösa vissa affärsproblem.
Därför ska vi ta reda på:
- Vad händer när en yttre transaktion återställs eller genomförs?
- Vad händer när en inre transaktion återställs eller genomförs?
- Hur hanterar man kapslade transaktionsfel?
Till att börja med kommer vi att skapa en demotabell och testa möjliga fall.
USE AdventureWorks -----Create Demo Table---- CREATE TABLE CodingSightDemo (NumberValue VARCHAR(20))
Fall 1:Både yttre och inre transaktioner är begärda.
TRUNCATE TABLE CodingSightDemo --<*************OUTHER TRANSACTION START*************> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') COMMIT TRAN --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
I det här fallet har alla poster framgångsrikt infogats i tabellen. Vi antog att varje INSERT-sats inte returnerar ett fel.
Fall 2:Yttre transaktion återställs , den inre transaktionen är begärd .
TRUNCATE TABLE CodingSightDemo --<*************OUTHER TRANSACTION START*************> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') rollback TRAN --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Som du kan se infogas inte posterna i tabellen eftersom den inre transaktionen är en del av den yttre transaktionen. Av denna anledning rullar den inre transaktionen tillbaka.
Fall 3:Yttre transaktion är begärd , den inre transaktionen rullas tillbaka .
TRUNCATE TABLE CodingSightDemo --<*************OUTHER TRANSACTION START*************> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') ROLLBACK TRAN --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') COMMIT TRAN --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
I det här fallet fick vi ett fel och infogade det senaste uttalandet i tabellen. Som ett resultat uppstår några frågor:
- Varför fick vi ett felmeddelande?
- Varför lades den senaste INSERT-satsen till i tabellen?
Som regel rullar ROLLBACK TRAN-satsen tillbaka alla öppna transaktioner som utförs i den aktuella sessionen. Vi kan inte skriva en fråga eftersom den kommer att returnera ett fel.
BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') ROLLBACK TRAN ROLLBACK TRAN
Vi kommer att undersöka hur denna regel kan påverka vårt fall. ROLLBACK TRAN-satsen rullar tillbaka inre och yttre transaktioner. Av denna anledning får vi ett felmeddelande när vi kör COMMIT TRAN-satsen eftersom det inte finns några öppna transaktioner.
Därefter kommer vi att lägga till en felhanteringssats till den här frågan och modifiera den baserat på den defensiva programmeringsmetoden (som Wikipedia säger:Defensiv programmering är en form av defensiv design avsedd att säkerställa den fortsatta funktionen av en mjukvara under oförutsedda omständigheter). När vi skriver en fråga utan att ta hand om felhanteringen och får ett fel, kan vi möta dataintegriteten.
Med nästa skript kommer vi att använda spara poäng. De markerar en punkt i transaktionen och om du vill kan du återställa alla DML-satser (Data Manipulation Language) till den markerade punkten.
BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> SAVE TRANSACTION innerTRAN BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN END TRY BEGIN CATCH IF XACT_STATE() <> 0 BEGIN ROLLBACK TRANSACTION innerTRAN PRINT 'Roll back occurs for inner tran' END IF XACT_STATE() <> 0 BEGIN COMMIT TRAN PRINT 'Commit occurs for firt open tran' END END CATCH --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') COMMIT TRAN END TRY BEGIN CATCH BEGIN IF XACT_STATE() <> 0 ROLLBACK TRAN PRINT 'Roll back occurs for outer tran' END END CATCH --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Denna fråga kommer att hantera felet när den inre transaktionen får ett fel. Även yttre transaktioner genomförs framgångsrikt. Men i vissa fall, om den inre transaktionen får ett fel, måste den yttre transaktionen rulla tillbaka. I det här fallet kommer vi att använda en lokal variabel som kommer att behålla och skicka det inre frågefeltillståndsvärdet. Vi kommer att designa den yttre frågan med detta variabelvärde och frågan blir som följer.
--<*************OUTHER TRANSACTION START*************> DECLARE @innertranerror as int=0 BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('One') --<INNER TRANSACTION START> SAVE TRANSACTION innerTRAN BEGIN TRY BEGIN TRAN INSERT INTO CodingSightDemo VALUES('Two') COMMIT TRAN END TRY BEGIN CATCH IF XACT_STATE() <> 0 BEGIN SET @innertranerror=1 ROLLBACK TRANSACTION innerTRAN PRINT 'Roll back occurs for inner tran' END IF XACT_STATE() <> 0 BEGIN COMMIT TRAN PRINT 'Commit occurs for firt open tran' END END CATCH --< INNER TRANSACTION END> INSERT INTO CodingSightDemo VALUES('Three') if @innertranerror=0 BEGIN COMMIT TRAN END IF @innertranerror=1 BEGIN ROLLBACK TRAN END END TRY BEGIN CATCH BEGIN IF XACT_STATE() <> 0 ROLLBACK TRAN PRINT 'Roll back occurs for outer tran' END END CATCH --<************* OUTHER TRANSACTION END*************> SELECT * FROM CodingSightDemo
Slutsatser
I den här artikeln utforskade vi kapslade transaktioner och analyserade hur man hanterar fel i den här typen av frågor. Den viktigaste regeln för denna transaktionstyp är att skriva defensiva frågor eftersom vi kan få ett fel i yttre eller inre transaktioner. Av denna anledning måste vi utforma felhanteringsbeteendet för frågan.
Referenser
Nästransaktioner
SPARA TRANSAKTION