transaction transacciones procedimientos ejemplos begin anidadas almacenados sql-server transactions entity-framework-6

sql server - procedimientos - El recuento de transacciones después de EXECUTE indica un número incorrecto de BEGIN y COMMIT



transacciones en sql server pdf (1)

También debe considerar los resultados de la función XACT_STATE (). Compruebe el bloque Transacciones no confirmables y XACT_STATE en MSDN

EDITAR MÁS TARDE

Cambié de opinión sobre una posible solución :) Finalmente conseguí reproducir tu situación. Mira. Tomé su procedimiento, eliminé todos los códigos, excepto el código relacionado con el manejo de excepciones, e try/catch lógica y la expresión agregada, lo que provocará un error en la resolución del nombre del objeto (error fatal). Esto es lo que obtuve

CREATE PROCEDURE [dbo].[proc_PurchaseOrder_Create] AS SET NOCOUNT ON; BEGIN TRY BEGIN TRAN print ''before'' select * from ##global_tmp_table; --> fatal error here print ''after'' COMMIT TRAN END TRY BEGIN CATCH print ''catch'' IF @@TRANCOUNT > 0 ROLLBACK END CATCH

Ok, ahora si trato de ejecutar este procedimiento obtuve la siguiente salida

antes Msg 208, nivel 16, estado 0, procedimiento proc_PurchaseOrder_Create, línea 29 Nombre de objeto no válido ''## global_tmp_table''. Msg 266, nivel 16, estado 2, procedimiento proc_PurchaseOrder_Create, línea 29 Recuento de transacciones después de EXECUTE indica un número incorrecto de instrucciones BEGIN y COMMIT. Recuento previo = 0, recuento actual = 1.

¿Entonces qué pasó? - Nuestra transacción permanece abierta ; puede verificar esto ejecutando print @@TRANCOUNT en la misma ventana

¿Por qué sucedió esto? - porque el bloque catch no puede detectar errores fatales - del mismo artículo de MSDN que mencioné anteriormente

Los siguientes tipos de errores no son manejados por un bloque CATCH cuando ocurren en el mismo nivel de ejecución que la construcción TRY ... CATCH: Compila errores, como errores de sintaxis, que impiden la ejecución de un lote. Errores que ocurren durante la recompilación de nivel de sentencia, como los errores de resolución de nombre de objeto que ocurren después de la compilación debido a la resolución diferida del nombre.

Antes de que arreglemos esta situación, debe llamar a ROLLBACK en la ventana donde intentó ejecutar el procedimiento almacenado para finalmente cerrar nuestra transacción.

¿Y cómo podemos arreglar eso? - solo tenemos que activar set XACT_ABORT ON - puede encontrar un ejemplo en el mismo artículo en el uso de TRY ... CATCH con el bloque XACT_STATE

Entonces, finalmente, nuestro procedimiento de prueba debería verse así

ALTER PROCEDURE [dbo].[proc_PurchaseOrder_Create] AS SET NOCOUNT ON; SET XACT_ABORT ON; --> the only change BEGIN TRY BEGIN TRAN print ''before'' select * from ##global_tmp_table; print ''after'' COMMIT TRAN END TRY BEGIN CATCH print ''catch'' IF @@TRANCOUNT > 0 ROLLBACK END CATCH

Y ahora, en un caso de motor de base de datos de error fatal, la transacción se retrotrae automáticamente y obtendrá solo el mensaje de error esperado

before Msg 208, Level 16, State 0, Procedure proc_PurchaseOrder_Create, Line 31 Nombre de objeto no válido ''## global_tmp_table''.

Cuando se produce un error en el siguiente proceso, el mensaje de error es "Recuento de transacciones después de que EXECUTE indica un número incorrecto de instrucciones BEGIN y COMMIT. count = 1, current count = 0 previo count = 1, current count = 0 El recuento de transacciones después de EXECUTE indica un número incorrecto de instrucciones BEGIN y COMMIT count = 1, current count = 0 previa count = 1, current count = 0 "

CREATE PROCEDURE [dbo].[proc_PurchaseOrder_Create](@CustomerID INT, @CustomerOrderID INT OUTPUT) AS SET NOCOUNT ON; -------------------------------- DECLARE @Return_Message VARCHAR(1024) DECLARE @ErrorCode INT DECLARE @ErrorStep VARCHAR(200) DECLARE @UserID INT -------------------------------- DECLARE @CustomerCartID INT,@PONumber VARCHAR(255), @CartTotalAmount NUMERIC BEGIN TRY BEGIN TRAN ----------------------------------------------------------------------------- SELECT @ErrorCode = @@ERROR SET NOCOUNT ON; IF NOT EXISTS(SELECT CustomerCartID FROM TxnCustomerCart WHERE CustomerID = @CustomerID) BEGIN SET @Return_Message= ''No Cart item is available'' SET @ErrorCode = 1 END ELSE BEGIN ----------------------------------------------------------------------------- SELECT @UserID = ISNULL(UserID,0) FROM TxnCustomers WHERE CustomerID = @CustomerID ----------------------------------------------------------------------------- SELECT @CartTotalAmount = CartTotalAmount, @CustomerCartID = CustomerCartID FROM TxnCustomerCart WHERE @CustomerID = CustomerID SELECT @ErrorStep = ''Error on inserting data into TxnCustomerOrders''; INSERT INTO TxnCustomerOrders(CustomerID,OrderDate,OrderStatus,Ramarks,PaymentCategoryCode,CreatedBy,CreatedDatetime) VALUES(@CustomerID,GETDATE(),''PRTRCVD'','''',''Wallet'',@UserID,GETDATE()) SET @CustomerOrderID = SCOPE_IDENTITY(); SELECT @ErrorStep = ''Error on generating PONumber''; SET @PONumber =dbo.fun_getPONumber(@CustomerID, @CustomerOrderID) SELECT @ErrorStep = ''Error on inserting data into TxnPurchaseOrder''; INSERT INTO TxnPurchaseOrder (CustomerOrderID, PONumber, PODate, POAmount, PODocID, PODocPath, CreatedBy, CreatedDate) VALUES (@CustomerOrderID, @PONumber, GETDATE(), @CartTotalAmount, REPLACE(@PONumber, ''/'' , ''-''), REPLACE(@PONumber, ''/'' , ''-'') + ''.pdf'', @UserID, GETDATE()) SELECT @ErrorCode = 0, @Return_Message = ''Purchase order successfully created'' END SET NOCOUNT OFF; COMMIT TRAN RETURN @ErrorCode -- =0 if success, <>0 if failure END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK SELECT @ErrorCode = ERROR_NUMBER() , @Return_Message = @ErrorStep + '' '' + cast(ERROR_NUMBER() as varchar(20)) + '' line: '' + cast(ERROR_LINE() as varchar(20)) + '' '' + ERROR_MESSAGE() + '' > '' + ERROR_PROCEDURE() RETURN @ErrorCode -- =0 if success, <>0 if failure END CATCH