2010-10-22 42 views
7

Tengo un procedimiento almacenado que tiene una instrucción BEGIN TRANSACTION y COMMIT TRANSACTION. Dentro de la transacción hay una consulta de selección WITH(XLOCK, ROWLOCK).Transacción de SQL Server 2008, ¿se requiere reversión?

La transacción puede fallar debido a algunos cálculos que causan un error de desbordamiento aritmético si se proporcionan valores fuera de límites. Este error ocurriría antes de cualquier instrucción de inserción/actualización.

Mi pregunta es, ¿debo envolver la transacción en un TRY/CATCH y revertir o esto no es realmente necesario y todos los bloqueos se liberarían automáticamente si la transacción falla? Mi única preocupación aquí es que SQL no liberaría todos los bloqueos de la transacción en caso de que la transacción falle.

Gracias,

Tom

Respuesta

6

Respuesta corta: Sí.

Siempre que uso BEGIN TRANSACTION, I siempre incluyen el uso de manejo de errores y ROLLBACK. Las consecuencias de golpear una situación no anticipada (y/o no anticipable - no se puede saber cómo se debe modificar su código en el futuro) que deja una transacción abierta en un servidor de producción son demasiado severas para no hacerlo.

En SQL Server 2000 y anteriores, debe usar @@ Error logic. En SQL 2005 en adelante, puedes usar la sintaxis TRY ... CATCH ... (muy superior).

3

TRY/CATCH no es necesaria para liberar los bloqueos. Sin embargo, creo que la siguiente plantilla sería buena para la mayoría de las transacciones.

BEGIN TRY 
    BEGIN TRAN 
    ... 
    IF (@@error <> 0) 
     ROLLBACK TRAN 
END TRY 
BEGIN CATCH 
    ROLLBACK TRAN 
END CATCH 
--BEGIN FINALLY (doesnt exist, which is why I commented it out)  
    IF (@@trancount > 0) 
     COMMIT TRAN 
--END FINALLY 
8

Una manera mucho más fácil es:

set xact_abort on 

Esto hará que la transacción se revierte automáticamente cuando se produce un error.

código Ejemplo:

set xact_abort on 
begin transaction 
select 1/0 
go 
print @@trancount -- Prints 0 

set xact_abort off 
begin transaction 
select 1/0 
go 
print @@trancount -- Prints 1 

Si se ejecuta el segundo segmento varias veces, verá el aumento de número de transacciones de 2,3,4 etc. Una sola ejecución del primer segmento restablece todas las transacciones.

5

Me gusta el enfoque de Brad pero necesitaba un poco de limpieza para que pueda ver el error que causó el problema.

begin try 
    begin transaction; 

    ... 

    commit transaction; 
end try 
begin catch 
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int; 
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); 
    rollback transaction; 
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState); 
end catch 
1
begin transaction; -- you don't want to hit catch block if begin transaction will fail 
begin try 

    ... updates/inserts/selects ... 

    commit transaction; -- the last statement in try code block is always commit 
end try 
begin catch 
    rollback transaction; -- first step before other error handling code is rollback transaction 
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int; 
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); 
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState); 
end catch 
Cuestiones relacionadas