2012-07-13 17 views
5

Fa un rollback all'interno di un INSERT DOPO o di un UPDATE DOPO il rollback del trigger dell'intera transazione o solo della riga corrente che è il motivo del trigger, ed è lo stesso con Commit?Un rollback all'interno di un INSERT DOPO o UPDATE DOPO innesca il rollback dell'intera transazione

Ho provato a controllarlo tramite il mio codice progetti corrente che utilizza MSTDC per le transazioni e sembra come se la transazione completa fosse stata interrotta.

Se un rollback nel trigger esegue il rollback dell'intera transazione, esiste una soluzione alternativa per limitare solo le righe correnti.

ho trovato un link per sybase su questo, ma nulla sul server di SQL

+1

Doe SQL Server consente effettivamente un 'rollback' in un trigger? –

+0

Suppongo di sì, b'coz ne ho scritto uno, e non ha generato alcun errore durante l'esecuzione dello script e anche il trigger funziona. – Vamsi

+1

Wow. Quello è spaventoso –

risposta

7

Sì, sarà il rollback l'intera transazione.

È tutto nel docs (vedere Note). Nota il commento che ho sottolineato - è piuttosto importante direi !!

Se una transazione ROLLBACK viene emesso in un trigger:

Tutte le modifiche dei dati apportate a quel punto nella transazione corrente rollback, comprese le eventuali fatta dal trigger.

Il trigger continua a eseguire tutte le istruzioni rimanenti dopo l'istruzione ROLLBACK . Se una qualsiasi di queste istruzioni modifica i dati, le modifiche non vengono ripristinate. Nessun trigger nidificato viene attivato dall'esecuzione di di queste istruzioni rimanenti.

Le istruzioni nel batch dopo l'istruzione che ha attivato il trigger non vengono eseguite.

+1

Quindi, qualsiasi soluzione alternativa? – Vamsi

+4

Perché dovresti avere bisogno di una soluzione alternativa? Un trigger è solo un codice come qualsiasi altro codice: controlli esattamente dove vuoi fare i rollback in ogni momento. – Jimbo

+0

Penso che quello che sta chiedendo sia il rollback delle sole righe coinvolte con l'istruzione insert/update che ha invocato il trigger. Per fare ciò, suppongo che sia necessario impostare un punto di salvataggio nel chiamante, chiamare l'insert/update, dal lato del trigger generare un errore in base a una logica se necessario, quindi nel chiamante rilevare l'errore e eseguire il rollback al punto di salvataggio . Non l'ho provato però. Un design migliore (senza eccezioni) potrebbe essere quello di verificare la condizione nel chiamante e nemmeno tentare di inserire/aggiornare quelle righe in primo luogo. – crokusek

0

Qualsiasi comando di rollback esegue il rollback di tutto fino a quando il tranout @@ è 0, a meno che non si specificino alcuni punti di salvataggio e non importa dove si inserisce il comando di rollback trans.

Il modo migliore è esaminare il codice ancora una volta e confermare i requisiti aziendali e vedere perché è necessario un rollback in trigger?

1

Come già vi è stato detto, il comando ROLLBACK non può essere modificato/ottimizzato in modo tale che si limitino a ripristinare le istruzioni emesse dal trigger.

Se è necessario un modo per "rollback" azioni eseguite dal trigger solo, è possibile, come soluzione alternativa, considerare la modifica del trigger in modo tale che prima di eseguire le azioni, il trigger si assicuri che tali azioni eseguano non produce situazioni eccezionali che potrebbero causare il rollback dell'intera transazione.

Ad esempio, se il trigger inserisce righe, aggiungere un segno di spunta per assicurarsi che le nuove righe non violino, ad es.vincoli unici (o vincoli di chiave esterna), qualcosa di simile:

IF NOT EXISTS (
    SELECT * 
    FROM TableA 
    WHERE … /* a condition to test if a row or rows you are about 
       to insert aren't going to violate any constraint */ 
) 
BEGIN 
    INSERT INTO TableA … 
END; 

O, se il trigger elimina le righe, verificare se non tenta di eliminare righe a cui fanno riferimento altre tabelle (in questo caso di solito è necessario sapere in anticipo quali tabelle Might riferimento le righe):

IF NOT EXISTS (
    SELECT * FROM TableB WHERE … 
) 
AND NOT EXISTS (
    SELECT * FROM TableC WHERE … 
) 
AND … 
BEGIN 
    DELETE FROM TableA WHERE … 
END 

Allo stesso modo, si avrebbe bisogno di effettuare controlli per le dichiarazioni di aggiornamento, se del caso.

Problemi correlati