Per impostazione predefinita, le transazioni, nella maggior parte dei casi, non vengono ripristinate / annullate automaticamente quando si verifica un errore. Questo di solito non è un problema, purché tu abbia una corretta gestione degli errori e ROLLBACK
ti chiami . Tuttavia, a volte le cose si complicano, come nel caso di errori di interruzione batch o quando si utilizza OPENQUERY
(o Server collegati in generale) e si verifica un errore sul sistema remoto. Mentre la maggior parte degli errori può essere intrappolata usando TRY...CATCH
, ce ne sono due che non possono essere intrappolati in quel modo (non ricordo quali al momento, però - ricercare). In questi casi, è necessario utilizzare SET XACT_ABORT ON
per ripristinare correttamente la transazione.
SET XACT_ABORT ON causa che SQL Server immediatamente roll-back ogni transazione (se uno è attivo) e interruzione del lotto se qualsiasi si verifica un errore. Questa impostazione esisteva prima di SQL Server 2005, che ha introdotto il TRY...CATCH
costrutto. Per la maggior parte, TRY...CATCH
gestisce la maggior parte delle situazioni e quindi per lo più oscura la necessità XACT_ABORT ON
. Tuttavia, quando si utilizza OPENQUERY
(e possibilmente un altro scenario che non ricordo al momento), sarà comunque necessario utilizzare SET XACT_ABORT ON;
.
Dovresti sempre avere una corretta gestione degli errori, specialmente quando utilizzi Transazioni. Il TRY...CATCH
costrutto, introdotto in SQL Server 2005, fornisce un mezzo per gestire quasi tutte le situazioni, un gradito miglioramento rispetto ai test per @@ERROR
ogni istruzione successiva, che non ha aiutato molto con errori di interruzione del batch.
TRY...CATCH
introdotto un nuovo "stato", tuttavia. Quando non si utilizza il TRY...CATCH
costrutto, se si dispone di una Transazione attiva e si verifica un errore, è possibile prendere diversi percorsi:
XACT_ABORT OFF
e errore di interruzione dell'istruzione: la transazione è ancora attiva e l'elaborazione continua con l'eventuale istruzione successiva .
XACT_ABORT OFF
e la maggior parte degli errori di interruzione batch: la transazione è ancora attiva e l'elaborazione continua con l'eventuale batch successivo .
XACT_ABORT OFF
e alcuni errori di interruzione del batch: la transazione viene ripristinata e l'elaborazione continua con l'eventuale batch successivo .
XACT_ABORT ON
e qualsiasi errore: la transazione viene ripristinata e l'elaborazione continua con il batch successivo , se presente.
TUTTAVIA, durante l'utilizzo TRY...CATCH
, gli errori di interruzione batch non interrompono il batch, ma trasferiscono invece il controllo al CATCH
blocco. Quando XACT_ABORT
è OFF
, l'Operazione sarà ancora attiva la maggior parte del tempo, e sarà necessario COMMIT
, o più probabilmente, ROLLBACK
. Ma quando si verificano determinati errori di interruzione batch (come con OPENQUERY
), o quando lo XACT_ABORT
è ON
, la Transazione sarà in un nuovo stato, "non credibile". In questo stato non è possibile COMMIT
né eseguire operazioni DML. Tutto quello che puoi fare è ROLLBACK
e SELECT
dichiarazioni. Tuttavia, in questo stato "inattendibile", la transazione è stata ripristinata in seguito all'errore che si verifica e l'emissione ROLLBACK
è solo una formalità, ma deve essere eseguita.
Una funzione, XACT_STATE , può essere utilizzata per determinare se una Transazione è attiva, non credibile o non esiste. Si consiglia (almeno da alcuni) di controllare questa funzione nel CATCH
blocco per determinare se il risultato è -1
(cioè non credibile) invece di testare se @@TRANCOUNT > 0
. Ma con XACT_ABORT ON
quello, dovrebbe essere l'unico stato possibile in cui trovarsi, quindi sembra che i test per @@TRANCOUNT > 0
e XACT_STATE() <> 0
siano equivalenti. D'altra parte, quando XACT_ABORT
c'è OFF
e c'è una Transazione attiva, allora è possibile avere uno stato di uno 1
o -1
nel CATCH
blocco, che consente la possibilità di emettere COMMIT
invece di ROLLBACK
(anche se, non riesco a pensare a un caso per quando qualcuno vorrebbeCOMMIT
se la transazione è commettibile). Ulteriori informazioni e ricerche sull'utilizzo XACT_STATE()
all'interno di un CATCH
blocco con XACT_ABORT ON
sono disponibili nella mia risposta alla seguente domanda DBA.SE: in quali casi è possibile eseguire il commit di una transazione dall'interno del blocco CATCH quando XACT_ABORT è impostato su ON? . Si noti che esiste un bug minore XACT_STATE()
che lo fa restituire erroneamente 1
in alcuni scenari: XACT_STATE () restituisce 1 se utilizzato in SELECT con alcune variabili di sistema ma senza la clausola FROM
spNewBilling3
genera un errore, ma non si desidera eseguire il rollbackspNewBilling2
ospNewBilling1
, quindi rimuoverlo[begin|rollback|commit] transaction createSavebillinginvoice
daspSavesomename
.