Por defecto, las transacciones, la mayoría de las veces, no se revierten / cancelan automáticamente cuando se produce un error. Por lo general, esto no es un problema siempre y cuando tenga un manejo adecuado de los errores y se llame a ROLLBACK
sí mismo. Sin embargo, a veces las cosas se complican, como en el caso de errores de aborto por lotes, o cuando se usa OPENQUERY
(o servidores vinculados en general) y se produce un error en el sistema remoto. Si bien la mayoría de los errores se pueden atrapar usando TRY...CATCH
, hay dos que no se pueden atrapar de esa manera (sin embargo, no puedo recordar cuáles en este momento, investigar). En estos casos, debe usar SET XACT_ABORT ON
para deshacer correctamente la transacción.
SET XACT_ABORT ON hace que SQL Server revierta inmediatamente cualquier transacción (si hay una activa) y cancela el lote si se produce algún error. Esta configuración existía antes de SQL Server 2005, que introdujo la TRY...CATCH
construcción. En su mayor parte, TRY...CATCH
maneja la mayoría de las situaciones y, por lo tanto, en su mayoría obsoletos la necesidad de XACT_ABORT ON
. Sin embargo, cuando lo use OPENQUERY
(y posiblemente otro escenario que no puedo recordar en este momento), aún tendrá que usarlo SET XACT_ABORT ON;
.
Siempre debe tener un manejo adecuado de los errores, especialmente al usar Transacciones. La TRY...CATCH
construcción, introducida en SQL Server 2005, proporciona un medio para manejar casi todas las situaciones, una mejora bienvenida sobre las pruebas para @@ERROR
después de cada declaración, que no ayudó mucho con los errores de aborto por lotes.
TRY...CATCH
introdujo un nuevo "estado", sin embargo. Cuando no se utiliza la TRY...CATCH
construcción, si tiene una transacción activa y se produce un error, se pueden tomar varias rutas:
XACT_ABORT OFF
y error de anulación de la declaración: la transacción aún está activa y el procesamiento continúa con la siguiente declaración , si corresponde.
XACT_ABORT OFF
y la mayoría de los errores de cancelación de lotes: la transacción aún está activa y el procesamiento continúa con el siguiente lote , si corresponde.
XACT_ABORT OFF
y ciertos errores de cancelación de lotes: la transacción se revierte y el procesamiento continúa con el siguiente lote , si corresponde.
XACT_ABORT ON
y cualquier error: la transacción se revierte y el procesamiento continúa con el siguiente lote , si corresponde.
SIN EMBARGO, cuando se usa TRY...CATCH
, los errores de aborto por lotes no abortan el lote, sino que transfieren el control al CATCH
bloque. Cuando XACT_ABORT
es OFF
, la transacción seguirá siendo activa la gran mayoría de las veces, y usted tendrá que COMMIT
, o lo más probable, ROLLBACK
. Pero cuando encuentre ciertos errores de aborto por lotes (como con OPENQUERY
), o cuando lo XACT_ABORT
esté ON
, la transacción estará en un nuevo estado, "no conmutable". En este estado no puede COMMIT
, ni puede hacer ninguna operación DML. Todo lo que puedes hacer es ROLLBACK
y SELECT
declaraciones. Sin embargo, en este estado "incompatible", la transacción fue revertida cuando se produjo el error, y emitirlo ROLLBACK
es solo una formalidad, pero debe hacerse.
Se puede usar una función, XACT_STATE , para determinar si una Transacción está activa, no se puede compartir o no existe. Se recomienda (por lo menos, algunos) verificar esta función en el CATCH
bloque para determinar si el resultado es -1
( es decir, no comunicable) en lugar de probar si @@TRANCOUNT > 0
. Pero con XACT_ABORT ON
, eso debería ser el único estado posible para estar, por lo que parece que las pruebas de @@TRANCOUNT > 0
y XACT_STATE() <> 0
son equivalentes. Por otro lado, cuando XACT_ABORT
hay OFF
y hay una Transacción activa, entonces es posible tener un estado de cualquiera 1
o -1
en el CATCH
bloque, lo que permite la posibilidad de emitir en COMMIT
lugar de ROLLBACK
(aunque, no puedo pensar en un caso cuando alguien querríaCOMMIT
si la transacción es commitable). Puede encontrar más información e investigación sobre el uso XACT_STATE()
dentro de un CATCH
bloque con XACT_ABORT ON
mi respuesta a la siguiente pregunta de DBA.SE: ¿En qué casos se puede confirmar una transacción desde dentro del bloque CATCH cuando XACT_ABORT se establece en ON? . Tenga en cuenta que hay un pequeño error XACT_STATE()
que hace que regrese falsamente 1
en ciertos escenarios: XACT_STATE () devuelve 1 cuando se usa en SELECT con algunas variables del sistema pero sin la cláusula FROM
spNewBilling3
emite un error, pero que no quieren volver rollospNewBilling2
ospNewBilling1
, a continuación, basta con retirar[begin|rollback|commit] transaction createSavebillinginvoice
a partirspSavesomename
.