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

spNewBilling3emite un error, pero que no quieren volver rollospNewBilling2ospNewBilling1, a continuación, basta con retirar[begin|rollback|commit] transaction createSavebillinginvoicea 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
ROLLBACKelCATCHbloque 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 TRANBEGIN TRAN, ya sea que se llame o no, el contador de transacciones se incrementa en 1.SELECT @@TRANCOUNT;COMMITcomando emitido cuando@@TRANCOUNTestá a 2 o más no hace más que reducir, uno a la vez, el contador de transacciones.COMMITse emite un@@TRANCOUNTa1Los 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 TRANno se puede deshacer, excepto mediante la emisión de unaROLLBACKtransacción completa.COMMITcuándo@@TRANCOUNTestá 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
ROLLBACKemisión sin nombre siempre revertirá TODAS las transacciones.Un
ROLLBACKemitido con un nombre debe corresponder a:suponiendo que no
SAVE TRANse 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 TRANemitido 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 Buna vez: Deshacerá "DML Query 4".@@TRANCOUNTsigue siendo 2.ROLLBACK TRAN Bdos veces: Deshacerá "DML Query 4" y luego error, ya que no hay un punto de guardado correspondiente para "B".@@TRANCOUNTsigue siendo 2.ROLLBACK TRAN Auna vez: Deshacerá "DML Query 4" y "DML Query 3".@@TRANCOUNTsigue siendo 2.ROLLBACK TRAN Ados veces: Deshacerá "DML Query 4", "DML Query 3" y "DML Query 2".@@TRANCOUNTsigue siendo 2.ROLLBACK TRAN Atres 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").@@TRANCOUNTahora es 0.COMMITuna vez:@@TRANCOUNTbaja a 1.COMMITuna vez y luegoROLLBACK TRAN Buna vez:@@TRANCOUNTbaja a 1. Luego deshacerá "DML Query 4" (demostrando que COMMIT no hizo nada).@@TRANCOUNTsigue 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
@@TRANCOUNTser el mismo que cuando se llamó. Es decir, no puedes:BEGIN TRANen el proceso sin comprometerlo, esperando comprometerse en el proceso de llamada / padre.ROLLBACKsi se inició una transacción explícita antes de que se llame al proceso, ya que volverá@@TRANCOUNTa 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/ROLLBACKen 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...CATCHconstrucció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
ROLLBACKsí 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 ONpara 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...CATCHconstrucción. En su mayor parte,TRY...CATCHmaneja 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_ABORTse 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...CATCHconstrucción, introducida en SQL Server 2005, proporciona un medio para manejar casi todas las situaciones, una mejora bienvenida sobre las pruebas para@@ERRORdespués de cada declaración, que no ayudó mucho con los errores de aborto por lotes.TRY...CATCHintrodujo un nuevo "estado", sin embargo. Cuando no se utiliza laTRY...CATCHconstrucción, si tiene una transacción activa y se produce un error, se pueden tomar varias rutas:XACT_ABORT OFFy 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 OFFy 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 OFFy 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 ONy 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 alCATCHbloque. CuandoXACT_ABORTesOFF, 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_ABORTesté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 esROLLBACKySELECTdeclaraciones. Sin embargo, en este estado "incompatible", la transacción fue revertida cuando se produjo el error, y emitirloROLLBACKes 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
CATCHbloque 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 > 0yXACT_STATE() <> 0son equivalentes. Por otro lado, cuandoXACT_ABORThayOFFy hay una Transacción activa, entonces es posible tener un estado de cualquiera1o-1en elCATCHbloque, lo que permite la posibilidad de emitir enCOMMITlugar deROLLBACK(aunque, no puedo pensar en un caso cuando alguien querríaCOMMITsi la transacción es commitable). Puede encontrar más información e investigación sobre el usoXACT_STATE()dentro de unCATCHbloque conXACT_ABORT ONmi 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 falsamente1en 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:
BEGINyENDalrededor de cadaEXECllamadafuente
Compile errors, such as syntax errors, that prevent a batch from runningyErrors 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 (EXECosp_executesql) para queTRY...CATCHpueda 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