Tengo un procedimiento almacenado que solo ejecuta 3 procedimientos almacenados dentro de ellos. Solo estoy usando 1 parámetro para almacenar si el SP maestro es exitoso.
Si el primer procedimiento almacenado funciona bien en el procedimiento almacenado maestro, pero el segundo procedimiento almacenado falla, entonces, ¿revertirá automáticamente todos los SP en el SP maestro o tengo que hacer algún comando?
Aquí está mi procedimiento:
CREATE PROCEDURE [dbo].[spSavesomename]
-- Add the parameters for the stored procedure here
@successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
begin Try
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN
EXEC [dbo].[spNewBilling1]
END
BEGIN
EXEC [dbo].[spNewBilling2]
END
BEGIN
EXEC [dbo].[spNewBilling3]
END
set @successful = 1
end Try
begin Catch
rollback transaction createSavesomename
insert into dbo.tblErrorMessage(spName, errorMessage, systemDate)
values ('spSavesomename', ERROR_MESSAGE(), getdate())
return
end Catch
commit transaction createSavesomename
return
END
GO
sql-server
stored-procedures
transaction
usuario2483342
fuente
fuente
spNewBilling3
emite un error, pero que no quieren volver rollospNewBilling2
ospNewBilling1
, a continuación, basta con retirar[begin|rollback|commit] transaction createSavebillinginvoice
a partirspSavesomename
.Respuestas:
Dado solo el código que se muestra en la pregunta, y suponiendo que ninguno de los tres subprocesos tenga un manejo explícito de transacciones, entonces sí, se detectará un error en cualquiera de los tres subprocesos y
ROLLBACK
elCATCH
bloque retrocederá todo del trabajo.PERO aquí hay algunas cosas a tener en cuenta sobre las transacciones (al menos en SQL Server):
Solo hay una transacción real (la primera), no importa cuántas veces llame
BEGIN TRAN
BEGIN TRAN
, ya sea que se llame o no, el contador de transacciones se incrementa en 1.SELECT @@TRANCOUNT;
COMMIT
comando emitido cuando@@TRANCOUNT
está a 2 o más no hace más que reducir, uno a la vez, el contador de transacciones.COMMIT
se emite un@@TRANCOUNT
a1
Los puntos de guardado permiten crear un subconjunto de trabajo dentro de la transacción que se puede deshacer.
SAVE TRAN {save_point_name}
comandoROLLBACK {save_point_name}
. (más sobre esto a continuación)SAVE TRAN {save_point_name}
, incluidos los puntos de guardado creados después de que se creó el que se está deshaciendo (de ahí el "anidamiento").SAVE TRAN
no se puede deshacer, excepto mediante la emisión de unaROLLBACK
transacción completa.COMMIT
cuándo@@TRANCOUNT
está en 2 o más, no tiene ningún efecto en los puntos guardados (porque, de nuevo, los niveles de transacción por encima de 1 no existen fuera de ese contador).No puede confirmar transacciones específicas con nombre. El "nombre" de la transacción, si se proporciona junto con el
COMMIT
, se ignora y solo existe para facilitar la lectura.Una
ROLLBACK
emisión sin nombre siempre revertirá TODAS las transacciones.Un
ROLLBACK
emitido con un nombre debe corresponder a:suponiendo que no
SAVE TRAN
se haya llamado a ninguna con el mismo nombre de transacción, esto revertirá TODAS las transacciones.este comportamiento "deshacerá" todos los cambios realizados desde que se llamó al más reciente
SAVE TRAN {save_point_name}
.SAVE TRAN
emitido comandos con su nombre, entonces cada ROLLBACK de ese nombre de transacción deshacerá cada punto de guardado hasta que no quede ninguno de ese nombre. Después de eso, un ROLLBACK emitido con ese nombre revertirá TODAS las transacciones.Por ejemplo, suponga que los siguientes comandos se ejecutaron en el orden mostrado:
Ahora, si emite (cada uno de los siguientes escenarios es independiente el uno del otro):
ROLLBACK TRAN B
una vez: Deshacerá "DML Query 4".@@TRANCOUNT
sigue siendo 2.ROLLBACK TRAN B
dos veces: Deshacerá "DML Query 4" y luego error, ya que no hay un punto de guardado correspondiente para "B".@@TRANCOUNT
sigue siendo 2.ROLLBACK TRAN A
una vez: Deshacerá "DML Query 4" y "DML Query 3".@@TRANCOUNT
sigue siendo 2.ROLLBACK TRAN A
dos veces: Deshacerá "DML Query 4", "DML Query 3" y "DML Query 2".@@TRANCOUNT
sigue siendo 2.ROLLBACK TRAN A
tres veces: Deshacerá "DML Query 4", "DML Query 3" y "DML Query 2". Luego, revertirá toda la transacción (todo lo que quedó fue "DML Query 1").@@TRANCOUNT
ahora es 0.COMMIT
una vez:@@TRANCOUNT
baja a 1.COMMIT
una vez y luegoROLLBACK TRAN B
una vez:@@TRANCOUNT
baja a 1. Luego deshacerá "DML Query 4" (demostrando que COMMIT no hizo nada).@@TRANCOUNT
sigue siendo 1.Nombres de transacciones y nombres de puntos de guardado:
Un procedimiento almacenado no es, en sí mismo, una transacción implícita. Cada consulta si no se ha iniciado una transacción explícita, es una transacción implícita. Es por eso que las transacciones explícitas en torno a consultas individuales no son necesarias a menos que pueda haber una razón programática para hacerlo
ROLLBACK
, de lo contrario, cualquier error en la consulta es una reversión automática de esa consulta.Cuando se llama a un procedimiento almacenado, debe salir con el valor de
@@TRANCOUNT
ser el mismo que cuando se llamó. Es decir, no puedes:BEGIN TRAN
en el proceso sin comprometerlo, esperando comprometerse en el proceso de llamada / padre.ROLLBACK
si se inició una transacción explícita antes de que se llame al proceso, ya que volverá@@TRANCOUNT
a 0.Si sale de un procedimiento almacenado con un recuento de transacciones que es mayor o menor que cuando se inició, obtendrá un error similar a:
Las variables de tabla, al igual que las variables normales, no están vinculadas por transacciones.
Con respecto al manejo de transacciones en procesos que se pueden llamar de forma independiente (y por lo tanto necesitan manejo de transacciones) o llamar desde otros procesos (por lo tanto, no se necesita manejo de transacciones): esto se puede lograr de dos maneras diferentes.
La forma en que lo he estado manejando durante varios años ahora que parece funcionar bien es solo
BEGIN
/COMMIT
/ROLLBACK
en la capa más externa. Las llamadas de subproc simplemente omiten los comandos de transacción. He esbozado a continuación lo que pongo en cada proceso (bueno, cada uno que necesita manejo de transacciones).DECLARE @InNestedTransaction BIT;
En lugar de simple
BEGIN TRAN
, hacer:En lugar de simple
COMMIT
, hacer:En lugar de simple
ROLLBACK
, hacer:Este método debería funcionar igual independientemente de si la transacción se inició en SQL Server o si se inició en la capa de la aplicación.
Para ver la plantilla completa de este manejo de Transacciones dentro de la
TRY...CATCH
construcción, vea mi respuesta a la siguiente pregunta de DBA.SE: ¿Estamos obligados a manejar Transacciones en Código C # así como en procedimientos almacenados .Más allá de los "conceptos básicos", hay algunos matices adicionales de las transacciones a tener en cuenta:
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 usaOPENQUERY
(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 usandoTRY...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 usarSET 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 deXACT_ABORT ON
. Sin embargo, cuando lo useOPENQUERY
(y posiblemente otro escenario que no puedo recordar en este momento), aún tendrá que usarloSET XACT_ABORT ON;
.Dentro de un activador,
XACT_ABORT
se establece implícitamente enON
. Esto provoca que cualquier error dentro del Trigger cancele toda la instrucción DML que activó el Trigger.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 laTRY...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 alCATCH
bloque. CuandoXACT_ABORT
esOFF
, la transacción seguirá siendo activa la gran mayoría de las veces, y usted tendrá queCOMMIT
, o lo más probable,ROLLBACK
. Pero cuando encuentre ciertos errores de aborto por lotes (como conOPENQUERY
), o cuando loXACT_ABORT
estéON
, la transacción estará en un nuevo estado, "no conmutable". En este estado no puedeCOMMIT
, ni puede hacer ninguna operación DML. Todo lo que puedes hacer esROLLBACK
ySELECT
declaraciones. Sin embargo, en este estado "incompatible", la transacción fue revertida cuando se produjo el error, y emitirloROLLBACK
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 conXACT_ABORT ON
, eso debería ser el único estado posible para estar, por lo que parece que las pruebas de@@TRANCOUNT > 0
yXACT_STATE() <> 0
son equivalentes. Por otro lado, cuandoXACT_ABORT
hayOFF
y hay una Transacción activa, entonces es posible tener un estado de cualquiera1
o-1
en elCATCH
bloque, lo que permite la posibilidad de emitir enCOMMIT
lugar deROLLBACK
(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 usoXACT_STATE()
dentro de unCATCH
bloque conXACT_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 errorXACT_STATE()
que hace que regrese falsamente1
en ciertos escenarios: XACT_STATE () devuelve 1 cuando se usa en SELECT con algunas variables del sistema pero sin la cláusula FROMNotas sobre el código original:
BEGIN
yEND
alrededor de cadaEXEC
llamadafuente
Compile errors, such as syntax errors, that prevent a batch from running
yErrors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
. Pero no ocurren con mucha frecuencia, y cuando encuentre una situación así, corríjala (si es un error en el código) o colóquela en un subproceso (EXEC
osp_executesql
) para queTRY...CATCH
pueda atraparla.Sí, si debido a algún código de reversión de error en la instrucción catch de su procedimiento almacenado maestro se ejecutará, revertirá todas las operaciones realizadas por cualquier instrucción directa o mediante cualquiera de sus procedimientos almacenados anidados en ella.
Incluso si no ha aplicado ninguna transacción explícita en sus procedimientos almacenados anidados, estos procedimientos almacenados utilizarán una transacción implícita y se confirmarán al finalizar, PERO ya sea que haya confirmado mediante una transacción explícita o implícita en procedimientos almacenados anidados, el motor de SQL Server lo ignorará y lo ignorará. deshaga todas las acciones de estos procedimientos almacenados anidados si el procedimiento almacenado maestro falla y la transacción se respalda.
Cada vez que la transacción se confirma o se revierte en función de la acción realizada al final de la transacción más externa. Si se confirma la transacción externa, las transacciones anidadas internas también se confirman. Si la transacción externa se revierte, todas las transacciones internas también se revierten, independientemente de si las transacciones internas se confirmaron o no individualmente.
Para referencia http://technet.microsoft.com/en-us/library/ms189336(v=sql.105).aspx
fuente