sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man hanterar fel i SQL Server-kapslade transaktioner

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


  1. Hur kan jag skicka e-post från PostgreSQL trigger?

  2. Använda ODBC med Salesforce och OneLogin Single Sign On (SSO)

  3. Hur krypterar man lösenordet i Oracle?

  4. PostgreSQL unnest() med elementnummer