Comprometiendo solo los cambios específicos realizados dentro de una TRANSACCIÓN que puede REINICIAR
-
03-07-2019 - |
Pregunta
Esta es una edición significativa de la pregunta original, por lo que es más concisa y cubre los puntos planteados por las respuestas existentes ...
¿Es posible realizar varios cambios en varias tablas, dentro de una sola transacción, y revertir solo algunos de los cambios?
En el TSQL a continuación, NO quisiera ninguno de los cambios realizados por " myLogSP " para siempre ser revertido. Pero todos los cambios realizados por los diversos myBusinessSPs deberían revertirse si es necesario.
BEGIN TRANSACTION
EXEC myLogSP
EXEC @err = myBusinessSPa
IF (@err <> 0) BEGIN ROLLBACK TRANSACTION RETURN -1 END
EXEC myLogSP
EXEC @err = myBusinessSPb
IF (@err <> 0) BEGIN ROLLBACK TRANSACTION RETURN -1 END
EXEC myLogSP
EXEC @err = myBusinessSPc
IF (@err <> 0) BEGIN ROLLBACK TRANSACTION RETURN -1 END
EXEC myLogSP
COMMIT TRANSACTION
RETURN 0
El orden es importante, los myLogSPs deben realizarse entre y después de los myBusinessSPs (los myLogSPs detectan los cambios realizados por los myBusinessSPs)
También es importante que todos los myBusinessSP se realicen dentro de una transacción para mantener la integridad de la base de datos y permitir que todos sus cambios se restituyan si es necesario.
Es como si quisiera que los myLogSP se comportaran como si no fueran parte de la transacción. Es solo un hecho inconveniente de que estén dentro de uno (en virtud de la necesidad de ser llamado entre los myBusinessSPs).
EDITAR:
La respuesta final es " no " ;, la única opción es rediseñar el código. Ya sea mediante el uso de variables de tabla para el registro (ya que las variables no se retrotraen) o rediseñar la lógica de negocios para No requerir transacciones ...
Solución
Utilice SAVEPOINT
s , por ejemplo,
BEGIN TRANSACTION
EXEC myLogSP
SAVE TRANSACTION savepointA
EXEC @err = myBusinessSPa
IF (@err <> 0) BEGIN
ROLLBACK TRANSACTION savepointA
COMMIT
RETURN -1
END
EXEC myLogSP
SAVE TRANSACTION savepointB
EXEC @err = myBusinessSPb
IF (@err <> 0) BEGIN
ROLLBACK TRANSACTION savepointB
COMMIT
RETURN -1
END
EXEC myLogSP
SAVE TRANSACTION savepointC
EXEC @err = myBusinessSPc
IF (@err <> 0) BEGIN
ROLLBACK TRANSACTION savepointC
COMMIT
RETURN -1
END
EXEC myLogSP
COMMIT TRANSACTION
EDIT
Según la información proporcionada hasta el momento (y mi comprensión de ello), parece que tendrá que volver a diseñar sus registros de SP, ya sea para usar variables o para usar archivos, o para permitir que se ejecuten después de la hecho 'como sigue:
BEGIN TRANSACTION
SAVE TRANSACTION savepointA
EXEC @err = myBusinessSPa
IF (@err <> 0) BEGIN
ROLLBACK TRANSACTION savepointA
EXEC myLogSPA -- the call to myBusinessSPa was attempted/failed
COMMIT
RETURN -1
END
SAVE TRANSACTION savepointB
EXEC @err = myBusinessSPb
IF (@err <> 0) BEGIN
ROLLBACK TRANSACTION savepointB
EXEC myLogSPA -- the call to myBusinessSPa originally succeeded
EXEC myLogSPB -- the call to myBusinessSPb was attempted/failed
COMMIT
RETURN -1
END
SAVE TRANSACTION savepointC
EXEC @err = myBusinessSPc
IF (@err <> 0) BEGIN
ROLLBACK TRANSACTION savepointC
EXEC myLogSPA -- the call to myBusinessSPa originally succeeded
EXEC myLogSPB -- the call to myBusinessSPb originally succeeded
EXEC myLogSPC -- the call to myBusinessSPc was attempted/failed
COMMIT
RETURN -1
END
EXEC myLogSPA -- the call to myBusinessSPa succeeded
EXEC myLogSPB -- the call to myBusinessSPb succeeded
EXEC myLogSPC -- the call to myBusinessSPc succeeded
COMMIT TRANSACTION
Otros consejos
Básicamente debes saltar fuera del contexto actual. Hay un par de maneras de hacer eso. Una (que nunca he intentado) es llamar al CLR para hacer la inserción.
Quizás una mejor manera sea el hecho de que las transacciones no afecten a las variables de la tabla. Por ejemplo:
CREATE TABLE dbo.Test_Transactions
(
my_string VARCHAR(20) NOT NULL
)
GO
DECLARE
@tbl TABLE (my_string VARCHAR(20) NOT NULL)
BEGIN TRANSACTION
INSERT INTO dbo.Test_Transactions (my_string) VALUES ('test point one')
INSERT INTO @tbl (my_string) VALUES ('test point two')
INSERT INTO dbo.Test_Transactions (my_string) VALUES ('test point three')
ROLLBACK TRANSACTION
INSERT INTO dbo.Test_Transactions (my_string) select my_string from @tbl
SELECT * FROM dbo.Test_Transactions
SELECT * FROM @tbl
GO
Tuvimos suerte con poner las entradas de registro en las variables de la tabla y luego insertarlas en las tablas reales después de la confirmación o la reversión.
Bien, si no está en SQL Server 2008, intente este método. Es desordenado y una solución alternativa, pero debería funcionar. La tabla #temp y la variable de la tabla deberían configurarse con la estructura de lo que devuelve el sp.
create table #templog (fie1d1 int, field2 varchar(10))
declare @templog table (fie1d1 int, field2 varchar(10))
BEGIN TRANSACTION
insert into #templog
Exec my_proc
insert into @templog (fie1d1, field2)
select t.* from #templog t
left join @templog t2 on t.fie1d1 = t2.fie1d1 where t2.fie1d1 is null
insert into templog
values (1, 'test')
rollback tran
select * from #templog
select * from templog
select * from @templog
Utilice SAVEPOINTS y NIVELES DE AISLAMIENTO DE TRANSACCIONES .
¿No sería la forma más fácil de mover la inserción del registro fuera de la transacción?
Realmente no tengo una respuesta para usted para el bloqueo de mesa, creo que ya tiene la respuesta, habrá have para ser un bloqueo de tabla porque la columna de identidad puede retroceder.
mueve la declaración BEGIN TRANSACTION a después de la primera inserción.
Tal vez podría colocar las inserciones / actualizaciones de las tablas de negocios en su propia transacción atómica t1 y envolver cada una de estas transacciones en otra transacción t2 que ejecute la actualización de la tabla de registro y t1 (las actualizaciones de la tabla de negocios) sin ningún retroceso. Por ejemplo:
BEGIN TRANSACTION t2
<insert to log>
<execute stored procedure p1>
END TRANSACTION t2
CREATE PROCEDURE p1
AS
BEGIN TRANSACTION t1
<insert to business tables>
<rollback t1 on error>
END TRANSACTION t1
Creo que cuando se deshace t1 en el procedimiento almacenado, esto dejará sin efecto la transacción de llamada t2.