xact_abort try sirve que para example ejemplos catch sql sql-server tsql

sql - try - xact_abort para que sirve



¿Por qué Sql Server sigue ejecutándose después de raiserror cuando xact_abort está activado? (4)

Como se señaló en MSDN , se debe usar la instrucción THROW lugar de RAISERROR .

Los dos se comportan de forma ligeramente diferente . Pero cuando XACT_ABORT está configurado en ON, entonces siempre debe usar el comando THROW .

Me sorprendió algo en TSQL. Pensé que si xact_abort estaba activado, llamaría algo así como

raiserror(''Something bad happened'', 16, 1);

detendría la ejecución del procedimiento almacenado (o cualquier lote).

Pero mi mensaje de error ADO.NET acaba de demostrar lo contrario. Recibí tanto el mensaje de error de error del mensaje de excepción, como el siguiente mensaje que se rompió después de eso.

Esta es mi solución (que es mi hábito de todos modos), pero no parece que sea necesario:

if @somethingBadHappened begin; raiserror(''Something bad happened'', 16, 1); return; end;

Los documentos dicen esto:

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

¿Eso significa que debo estar usando una transacción explícita?


Esto es por diseño TM , como puede ver en la respuesta del equipo Connect by SQL Server a una pregunta similar:

Gracias por tus comentarios. Por diseño, la opción de conjunto XACT_ABORT no afecta el comportamiento de la instrucción RAISERROR. Consideraremos sus comentarios para modificar este comportamiento para una versión futura de SQL Server.

Sí, esto es un problema para algunos que esperaban que RAISERROR con una gran gravedad (como 16 ) fuera igual a un error de ejecución de SQL, no lo es.

Su solución alternativa es solo lo que debe hacer, y el uso de una transacción explícita no tiene ningún efecto en el comportamiento que desea cambiar.


Si usa un bloque try / catch, un número de error de error de gravedad de 11-19 hará que la ejecución salte al bloque catch.

Cualquier gravedad superior a 16 es un error del sistema. Para demostrar el siguiente código establece un bloque try / catch y ejecuta un procedimiento almacenado que suponemos que fallará:

supongamos que tenemos una tabla [dbo]. [Errores] para contener errores supongamos que tenemos un procedimiento almacenado [dbo]. [AssumeThisFails] que fallará cuando lo ejecutemos

-- first lets build a temporary table to hold errors if (object_id(''tempdb..#RAISERRORS'') is null) create table #RAISERRORS (ErrorNumber int, ErrorMessage varchar(400), ErrorSeverity int, ErrorState int, ErrorLine int, ErrorProcedure varchar(128)); -- this will determine if the transaction level of the query to programatically determine if we need to begin a new transaction or create a save point to rollback to declare @tc as int; set @tc = @@trancount; if (@tc = 0) begin transaction; else save transaction myTransaction; -- the code in the try block will be executed begin try declare @return_value = ''0''; set @return_value = ''0''; declare @ErrorNumber as int, @ErrorMessage as varchar(400), @ErrorSeverity as int, @ErrorState as int, @ErrorLine as int, @ErrorProcedure as varchar(128); -- assume that this procedure fails... exec @return_value = [dbo].[AssumeThisFails] if (@return_value <> 0) raiserror(''This is my error message'', 17, 1); -- the error severity of 17 will be considered a system error execution of this query will skip the following statements and resume at the begin catch block if (@tc = 0) commit transaction; return(0); end try -- the code in the catch block will be executed on raiserror("message", 17, 1) begin catch select @ErrorNumber = ERROR_NUMBER(), @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(), @ErrorLine = ERROR_LINE(), @ErrorProcedure = ERROR_PROCEDURE(); insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure) values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure); -- if i started the transaction if (@tc = 0) begin if (XACT_STATE() <> 0) begin select * from #RAISERRORS; rollback transaction; insert into [dbo].[Errors] (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure) select * from #RAISERRORS; insert [dbo].[Errors] (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure) values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure); return(1); end end -- if i didn''t start the transaction if (XACT_STATE() = 1) begin rollback transaction myTransaction; if (object_id(''tempdb..#RAISERRORS'') is not null) insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure) values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure); else raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState); return(2); end else if (XACT_STATE() = -1) begin rollback transaction; if (object_id(''tempdb..#RAISERRORS'') is not null) insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure) values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure); else raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState); return(3); end end catch end


Use RETURN inmediatamente después de RAISERROR() y no ejecutará más el procedimiento.