sql >> Database >  >> RDS >> Sqlserver

Hoe om te gaan met fouten in in SQL Server geneste transacties

In dit artikel gaan we in op SQL Server Nested Transactions, een transactieblok met een of meerdere transacties.

De afbeelding beschrijft een eenvoudig model van de geneste transactie.

De innerlijke transactie is een opgeslagen procedure die bestaat uit transactieblokken. MSDN beveelt aan om "transacties zo kort mogelijk te houden", wat totaal tegengesteld is aan de eerste benadering. Naar mijn mening raad ik het gebruik van geneste transacties niet aan. Toch moeten we ze soms gebruiken om zakelijke problemen op te lossen.

Zo gaan we uitzoeken:

  • Wat gebeurt er als een externe transactie wordt teruggedraaid of vastgelegd?
  • Wat gebeurt er als een interne transactie wordt teruggedraaid of vastgelegd?
  • Hoe om te gaan met fouten in geneste transacties?

Om te beginnen zullen we een demotabel maken en mogelijke cases testen.

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

Geval 1:Zowel uiterlijke als innerlijke transacties zijn toegezegd.

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

In dit geval zijn alle records met succes in de tabel ingevoegd. We gingen ervan uit dat elke INSERT-instructie geen fout retourneert.

Geval 2:Uiterlijke transactie wordt teruggedraaid , innerlijke transactie is toegezegd .

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

Zoals u kunt zien, worden de records niet in de tabel ingevoegd omdat de binnentransactie een onderdeel is van de buitentransactie. Om deze reden wordt de interne transactie teruggedraaid.

Geval 3:Uiterlijke transactie is toegezegd , interne transactie is teruggedraaid .

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

In dit geval hebben we een foutmelding gekregen en hebben we de laatste instructie in de tabel ingevoegd. Als gevolg hiervan rijzen er enkele vragen:

  • Waarom hebben we een foutmelding gekregen?
  • Waarom is het laatste INSERT-statement aan de tabel toegevoegd?

In de regel worden met het ROLLBACK TRAN-statement alle openstaande transacties die in de huidige sessie zijn uitgevoerd, teruggedraaid. We kunnen geen query schrijven omdat deze een fout retourneert.

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

We zullen onderzoeken hoe deze regel onze zaak kan beïnvloeden. Het ROLLBACK TRAN-statement maakt interne en externe transacties terug. Om deze reden krijgen we een foutmelding bij het uitvoeren van de COMMIT TRAN-instructie omdat er geen openstaande transacties zijn.

Vervolgens zullen we een foutafhandelingsverklaring aan deze query toevoegen en deze aanpassen op basis van de defensieve programmeerbenadering (zoals Wikipedia stelt:Defensief programmeren is een vorm van defensief ontwerp bedoeld om de continue functie van een stuk software onder onvoorziene omstandigheden te garanderen). Wanneer we een query schrijven zonder rekening te houden met foutafhandeling en een foutmelding krijgen, kunnen we te maken krijgen met corruptie van gegevensintegriteit.

Bij het volgende script gaan we spaarpunten gebruiken. Ze markeren een punt in de transactie en als u wilt, kunt u alle DML-instructies (Data Manipulation Language) terugdraaien naar het gemarkeerde punt.

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

Deze query zal de fout afhandelen wanneer de interne transactie een fout krijgt. Ook worden externe transacties met succes vastgelegd. In sommige gevallen, als de interne transactie een fout krijgt, moet de buitenste transactie echter worden teruggedraaid. In dit geval gebruiken we een lokale variabele die de waarde van de interne queryfoutstatus behoudt en doorgeeft. We zullen de buitenste query ontwerpen met deze variabele waarde en de query zal als volgt zijn.

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

Conclusies

In dit artikel hebben we geneste transacties onderzocht en geanalyseerd hoe fouten in dit type query kunnen worden afgehandeld. De belangrijkste regel over dit transactietype is om defensieve vragen te schrijven omdat we een fout kunnen krijgen in uiterlijke of innerlijke transacties. Om deze reden moeten we het foutafhandelingsgedrag van de query ontwerpen.

Referenties

Transacties nesten

TRANSACTIE OPSLAAN


  1. Illegale mix van sorteringen (utf8_unicode_ci,IMPLICIT) en (utf8_general_ci,IMPLICIT) voor bewerking '='

  2. TAN() Voorbeelden in SQL Server

  3. Queryresultaten exporteren naar een XML-bestand bij gebruik van SQLcl (Oracle)

  4. Tips en trucs voor het navigeren door de PostgreSQL-gemeenschap