2012-06-08 12 views
17

Si estoy codificando un procedimiento de SQL Server (2008r2) y lo envuelvo en una transacción, ¿tengo que incluirlo explícitamente en un bloque try..catch y luego llamar explícitamente a la reversión en el bloque catch, o lo hará salir y retroceder el mismo por su cuenta?¿Debo usar un bloque try..catch y una reversión explícita en un procedimiento de SQL Server?

es decir .:

¿Cómo funciona esto:

begin transaction 

    begin try 
    delete from.... 

    insert into... 
    end try 
    begin catch 
    rollback transaction 
    return 
    end catch 

    commit transaction 

Comparar con:

begin transaction 
    delete from.... 

    insert into... 
    commit transaction 

Gracias por cualquier ayuda.

Respuesta

19

La respuesta a su pregunta depende de la configuración SET XACT_ABORT:

Especifica si SQL Server revierte automáticamente la corriente de transacciones cuando una instrucción de Transact-SQL genera un error en tiempo de ejecución.

Cuando SET XACT_ABORT está activado, si una instrucción de Transact-SQL genera un error de tiempo de ejecución de , la transacción finaliza y se retrotrae.

Cuando SET XACT_ABORT está desactivado, en algunos casos solo se retrotrae la instrucción Transact-SQL que generó el error y la transacción continúa el procesamiento. Dependiendo de la gravedad del error, la transacción completa se puede deshacer incluso cuando SET XACT_ABORT esté desactivado. OFF es la configuración predeterminada.

Los errores de compilación, como los errores de sintaxis, no se ven afectados por SET XACT_ABORT.

Por ejemplo, intente con el siguiente código. La primera división por 0 genera un error pero continúa la ejecución. La segunda división por cero levanta una mano detiene la ejecución de error:

begin transaction 

set xact_abort off 

select 1/0 -- causes divide by zero error, but continues 
select @@trancount -- returns 1 

set xact_abort on 

select 1/0 -- causes divide by zero error and terminates execution 
select @@trancount -- we never get here 

rollback 

Si XACT_ABORT está en ON, a continuación, los errores se abortará la transacción, y que no necesitan un try/catch.

Si XACT_ABORT está en OFF, tendrá que comprobar el estado de cada declaración para ver si se ha producido un error:

begin transaction 

delete from... 
if @@error <> 0 
begin 
    if @@trancount > 0 
     rollback 
    return 
end 

insert into... 
if @@error <> 0 
begin 
    if @@trancount > 0 
     rollback 
    return 
end 

commit 

Sin embargo, si alguna vez encontrar un caso en el que hay que probar/CATCH, se puede necesitar hacer algo especial cuando ocurre el error. Si es así, no te olvides de TRY/CATCH el manejo de excepciones:

begin transaction 

set xact_abort on 

begin try 
    select 1/0 -- causes divide by zero error and terminates execution 
    select @@trancount -- we never get here 
    commit 
end try 
begin catch 
    select xact_state() -- this will be -1 indicating you MUST rollback before doing any other operations 
    select @@trancount -- this will probably be one, because we haven't ended the transaction yet 
    if xact_state() <> 0 
    begin try 
     select 'rollback' 
     rollback 

     -- do something to handle or record the error before leaving the current scope 
     select 'exception processing here' 
     --insert into... 
    end try 
    begin catch 
     -- ignore rollback errors 
    end catch 

end catch 
4

reversiones se producen automáticamente si hay un error EN CASOS mayoría pero no todos

si se quiere garantizar un retroceso para todos los errores preceden a la operación comenzará con SET XACT_ABORT EN

mejor práctica es explícitamente detectar errores con un bloque try-catch y tomar medidas allí, incluyendo quizás una reversión y reportar/registrar el error.

0

Depende del nivel de gravedad del error. Suficientemente alto - 16, tal vez? - el proceso puede detenerse en la línea que falla, dejando la transacción abierta y sus bloqueos en su lugar. Si hay alguna posibilidad de error dentro de una transacción, definitivamente desea envolverlo en el bloque try-catch, como lo hizo en su primer ejemplo.

Cuestiones relacionadas