sql >> Database teknologi >  >> RDS >> Sqlserver

Sådan håndteres fejl i SQL Server-indlejrede transaktioner

I denne artikel vil vi udforske SQL Server Nested Transactions, en transaktionsblok med en eller flere transaktioner.

Billedet beskriver en simpel model af den indlejrede transaktion.

Den indre transaktion er en lagret procedure, der består af transaktionsblokke. MSDN anbefaler "at holde transaktioner så korte som muligt", hvilket er totalt modsat den første tilgang. Efter min mening anbefaler jeg ikke at bruge indlejrede transaktioner. Alligevel er vi nogle gange nødt til at bruge dem til at løse nogle forretningsproblemer.

Derfor skal vi finde ud af:

  • Hvad sker der, når en ydre transaktion rulles tilbage eller forpligtes?
  • Hvad sker der, når en indre transaktion rulles tilbage eller forpligtes?
  • Hvordan håndterer man indlejrede transaktionsfejl?

Til at begynde med vil vi oprette en demo-tabel og teste mulige cases.

USE AdventureWorks
-----Create Demo Table----
CREATE TABLE CodingSightDemo
(NumberValue VARCHAR(20))

Case 1:Både ydre og indre transaktioner er forpligtet.

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 dette tilfælde er alle posterne indsat i tabellen. Vi antog, at hver INSERT-sætning ikke returnerer en fejl.

Tilfælde 2:Ydre transaktion er rullet tilbage , indre transaktion er forpligtet .

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, er posterne ikke indsat i tabellen, fordi den indre transaktion er en del af den ydre transaktion. Af denne grund ruller den indre transaktion tilbage.

Tilfælde 3:Ydre transaktion er forpligtet , indre transaktion rulles tilbage .

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 dette tilfælde fik vi en fejl og indsatte den seneste erklæring i tabellen. Som følge heraf opstår nogle spørgsmål:

  • Hvorfor fik vi en fejl?
  • Hvorfor blev den seneste INSERT-sætning føjet til tabellen?

Som regel ruller ROLLBACK TRAN-sætningen alle åbne transaktioner tilbage, der er udført i den aktuelle session. Vi kan ikke skrive en forespørgsel, fordi den vil returnere en fejl.

BEGIN TRAN
INSERT INTO CodingSightDemo	
VALUES('One')	
BEGIN TRAN
INSERT INTO CodingSightDemo	
VALUES('Two')	
ROLLBACK TRAN
ROLLBACK TRAN

Vi vil undersøge, hvordan denne regel kan påvirke vores sag. ROLLBACK TRAN-sætningen ruller indre og ydre transaktioner tilbage. Af denne grund får vi en fejl, når vi kører COMMIT TRAN-sætningen, fordi der ikke er nogen åbne transaktioner.

Dernæst vil vi tilføje en fejlhåndteringserklæring til denne forespørgsel og ændre den baseret på den defensive programmeringstilgang (som Wikipedia siger:Defensiv programmering er en form for defensivt design beregnet til at sikre den fortsatte funktion af et stykke software under uforudsete omstændigheder). Når vi skriver en forespørgsel uden at tage os af fejlhåndtering og får en fejl, kan vi blive udsat for korruption af dataintegriteten.

Med det næste script vil vi bruge sparepoint. De markerer et punkt i transaktionen, og hvis du vil, kan du rulle alle DML-udsagn (Data Manipulation Language) tilbage til det markerede punkt.

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

Denne forespørgsel vil håndtere fejlen, når den indre transaktion får en fejl. Også ydre transaktioner er begået med succes. Men i nogle tilfælde, hvis den indre transaktion får en fejl, skal den ydre transaktion rulle tilbage. I dette tilfælde vil vi bruge en lokal variabel, der vil beholde og videregive den indre forespørgselsfejltilstandsværdi. Vi designer den ydre forespørgsel med denne variabelværdi, og forespørgslen vil være som følger.

--<*************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

Konklusioner

I denne artikel undersøgte vi indlejrede transaktioner og analyserede, hvordan man håndterer fejl i denne type forespørgsel. Den vigtigste regel om denne transaktionstype er at skrive defensive forespørgsler, fordi vi kan få en fejl i ydre eller indre transaktioner. Af denne grund er vi nødt til at designe fejlhåndteringsadfærd for forespørgslen.

Referencer

Indlejringstransaktioner

GEM TRANSAKTION


  1. Hvordan kan jeg importere en database med MySQL fra terminal?

  2. Oracle Cloud:Oprettelse af en ATP-database (Autonomous Transaction Processing).

  3. Skift prioritet for en konto i en database-mailprofil (SSMS)

  4. Sådan udføres en lagret procedure i C#-programmet