sql >> Databáze >  >> RDS >> Sqlserver

Jak ošetřit chyby ve vnořených transakcích SQL Server

V tomto článku prozkoumáme SQL Server Nested Transactions, transakční blok s jednou nebo několika transakcemi.

Obrázek popisuje jednoduchý model vnořené transakce.

Vnitřní transakce je uložená procedura, která se skládá z transakčních bloků. MSDN doporučuje „udržovat transakce co nejkratší“, což je zcela opačný postup než u prvního přístupu. Dle mého názoru nedoporučuji používat vnořené transakce. Přesto je někdy musíme použít k řešení některých obchodních problémů.

Takže zjistíme:

  • Co se stane, když je vnější transakce odvolána nebo potvrzena?
  • Co se stane, když je vnitřní transakce vrácena zpět nebo potvrzena?
  • Jak zacházet s chybami vnořených transakcí?

Nejprve vytvoříme ukázkovou tabulku a otestujeme možné případy.

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

Případ 1:Vnější i vnitřní transakce jsou potvrzeny.

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

V tomto případě jsou všechny záznamy úspěšně vloženy do tabulky. Předpokládali jsme, že každý příkaz INSERT nevrací chybu.

Případ 2:Vnější transakce je odvolána , vnitřní transakce je potvrzena .

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

Jak vidíte, záznamy se do tabulky nevkládají, protože vnitřní transakce je součástí vnější transakce. Z tohoto důvodu se vnitřní transakce vrátí zpět.

Případ 3:Vnější transakce je potvrzena , vnitřní transakce je vrácena zpět .

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

V tomto případě jsme dostali chybu a do tabulky vložili nejnovější výpis. V důsledku toho vyvstávají některé otázky:

  • Proč se zobrazila chyba?
  • Proč byl do tabulky přidán nejnovější příkaz INSERT?

Příkaz ROLLBACK TRAN zpravidla vrátí zpět všechny otevřené transakce provedené v aktuální relaci. Nemůžeme napsat dotaz, protože vrátí chybu.

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

Prozkoumáme, jak toto pravidlo může ovlivnit náš případ. Příkaz ROLLBACK TRAN vrátí zpět vnitřní a vnější transakce. Z tohoto důvodu se při spuštění příkazu COMMIT TRAN zobrazí chyba, protože neexistují žádné otevřené transakce.

Dále k tomuto dotazu přidáme příkaz pro zpracování chyb a upravíme jej na základě přístupu defenzivního programování (jak uvádí Wikipedie:Defenzivní programování je forma defenzivního návrhu, která má zajistit trvalou funkci části softwaru za nepředvídaných okolností). Když napíšeme dotaz, aniž bychom se starali o zpracování chyb, a dostaneme chybu, můžeme čelit porušení integrity dat.

S dalším skriptem použijeme body uložení. Označují bod v transakci a pokud chcete, můžete vrátit všechny příkazy DML (Data Manipulation Language) do označeného bodu.

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

Tento dotaz zpracuje chybu, když vnitřní transakce dostane chybu. Také vnější transakce jsou úspěšně potvrzeny. V některých případech však dojde k chybě vnitřní transakce, vnější transakce se musí vrátit zpět. V tomto případě použijeme lokální proměnnou, která zachová a předá vnitřní hodnotu chybového stavu dotazu. Navrhneme vnější dotaz s touto hodnotou proměnné a dotaz bude následující.

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

Závěry

V tomto článku jsme prozkoumali vnořené transakce a analyzovali, jak zacházet s chybami v tomto typu dotazu. Nejdůležitějším pravidlem u tohoto typu transakce je psát obranné dotazy, protože můžeme získat chybu ve vnějších nebo vnitřních transakcích. Z tohoto důvodu musíme navrhnout chování při zpracování chyb v dotazu.

Odkazy

Vnořené transakce

ULOŽIT TRANSAKCI


  1. Výkon dávkového vkládání JDBC

  2. Spustit uloženou proceduru z funkce

  3. Může pole tabulky obsahovat spojovník?

  4. Jak porovnám 2 řádky ze stejné tabulky (SQL Server)?