2015-05-17 16 views
6

Ho un trigger INSERT su una delle mie tabelle che emette un THROW quando trova un duplicato. Il problema è che le transazioni sembrano essere implicitamente rallentate a questo punto - questo è un problema, voglio controllare quando le transazioni vengono fatte tornare indietro.SQL Server Ripristina la transazione quando si utilizza THROW

Il problema può essere ri-creato con questo script:

CREATE TABLE xTable (
     id int identity not null 
) 
go 
create trigger xTrigger on xTable after insert as 
print 'inserting...'; 
throw 1600000, 'blah', 1 
go 

begin tran 
insert into xTable default values 
rollback tran 

go 
drop table xTable 

Se si esegue il rollback tran - ti dirà non c'è si cominciano tran.

Se scambio il THROW per un'eccezione "normale" (come SELECT 1/0), la transazione non viene ripristinata.

Ho controllato il flag xact_abort ed è spento.

Utilizzo di SQL Server 2012 e la sperimentazione attraverso SSMS

Qualsiasi aiuto apprezzato, grazie.

EDIT Dopo aver letto gli articoli pubblicati da @ Dan Guzman, sono giunto alla seguente conclusione/sintesi ...

SQL Server imposta automaticamente XACT_ABORT ON nei trigger.

Il mio esempio (sopra) non illustra la mia situazione - In realtà sto creando un vincolo esteso utilizzando un trigger.

Il mio caso d'uso è stato inventato, stavo cercando di testare più situazioni nel test di unità SAME (non una situazione reale, e NON una buona pratica di test unitario).

La mia gestione del controllo esteso del vincolo e il lancio di un errore nel trigger sono corretti, tuttavia non esiste una situazione reale in cui non vorrei effettuare il rollback della transazione.

Può essere utile impostare XACT_ABORT OFF all'interno di un trigger per un caso particolare; ma la tua transazione sarà comunque compromessa da errori generali di interruzione del batch (come deadlock).

Ragioni storiche a parte, non sono d'accordo con la gestione di questo da parte di SQL Server; solo perché non esiste una situazione attuale in cui desideri continuare la transazione, non significa che una situazione del genere non possa sorgere. Mi piacerebbe vedere uno in grado di configurare SQL Server per mantenere l'integrità delle transazioni, se l'architettura scelta deve avere transazioni strettamente gestite all'origine, cioè "solo lui che avvia la transazione, deve terminarlo". Questo, a parte i soliti fail-safe, ad es. se il codice non viene mai raggiunto a causa di un errore di sistema, ecc.

risposta

4

THROW terminerà il batch al di fuori dell'ambito di TRY/CATCH (https://msdn.microsoft.com/en-us/library/ee677615.aspx). L'implicazione qui è che non avviene alcuna ulteriore elaborazione del lotto, comprese le dichiarazioni successive all'inserto. Avrai bisogno di circondare il tuo INSERT con un TRY/CATCH o utilizzare RAISERROR anziché THROW.

La gestione degli errori T-SQL è un argomento piuttosto ampio e complesso. Vi suggerisco di esaminare la serie di articoli per la gestione degli errori di Erland Sommarskog: http://www.sommarskog.se/error_handling/Part1.html. Più rilevante qui è l'argomento Can I Prevent the Trigger from Rolling Back the Transaction?http://www.sommarskog.se/error_handling/Part3.html#Triggers. La rimozione dal punto di vista delle migliori pratiche è che i trigger non sono la soluzione giusta se si applicano regole di business in un trigger senza rollback.

+0

Nice articoli - grazie Dan. @ usr, i trigger devono essere a livello di DB, fanno parte dei vincoli estesi. In un sistema con più client (incluso SSIS), non è possibile applicare il controllo ovunque. Il mio esempio non ha fornito tutti i dettagli del controllo dei vincoli. Né Dan né l'articolo dicono di non lanciare errori in un trigger, dicono di non provare a sopprimere il rollback. – Gilbert

Problemi correlati