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