【发布时间】:2022-01-05 16:28:31
【问题描述】:
我有两个过程,一个外部过程和一个内部过程,我想了解错误处理的行为。内部过程引发错误并试图将 catch 块中的某些内容插入到表中。之后引发错误,传递给外部过程,然后回滚事务。
我试图了解为什么我的代码会抛出错误消息:
Msg 50000, Level 11, State 1, Procedure dbo.OuterProcedure, Line 21 [Batch Start Line 9]
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
我希望收到以下消息:
Msg 50000, Level 11, State 1, Procedure dbo.OuterProcedure, Line 21 [Batch Start Line 9]
Error converting data type varchar to numeric.
我知道问题来自内部过程中的 catch 块,它发生是因为我试图在引发错误之前将某些内容插入到我的日志表中。当我切换这些语句或删除插入时,我会收到实际的错误消息。我也知道在内部过程和无论如何都回滚的事务中进行日志记录是不明智的。
即使 XACT_ABORT 设置为关闭,我想了解是什么导致此交易成为“注定”的交易。
完整代码:
我的主要程序:
CREATE PROCEDURE [dbo].[OuterProcedure]
AS
BEGIN
SET XACT_ABORT OFF;
BEGIN TRY
BEGIN TRANSACTION ;
-- do other stuff
EXEC [dbo].[innerprocedure];
-- do other stuff
COMMIT TRANSACTION ;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
DECLARE @ErrText NVARCHAR(2000);
SET @ErrText = ISNULL(ERROR_MESSAGE(), 'nothing')
RAISERROR(@ErrText, 11, 1) WITH NOWAIT
END CATCH;
END;
我的内心程序:
CREATE PROCEDURE [dbo].[InnerProcedure]
AS
BEGIN
SET XACT_ABORT OFF;
SET NOCOUNT ON;
BEGIN TRY
-- do other stuff
-- provoke error
SELECT
CASE
WHEN 1 = 0
THEN 0.0
ELSE ''
END;
-- do other stuff
END TRY
BEGIN CATCH
DECLARE @ErrText NVARCHAR(2000);
SELECT
@ErrText = ISNULL(ERROR_MESSAGE(), 'nothing');
INSERT INTO [dbo].[logtable]
(
[Message]
, [ErrNr]
)
VALUES
( @ErrText
, -1
);
RAISERROR(@LogText, 11, 0) WITH NOWAIT;
END CATCH;
END;
【问题讨论】:
-
以上内容不太现实。为什么在外部过程中没有任何事务性的显式事务?事务应该在内部查询中。当您收到错误时,会将
INSERT写入表logtable,然后当错误到达外部过程时,它会被it's 错误处理程序回滚。 -
你也应该使用
THROW。RAISERROR不尊重SET XACT_ABORT,根据 documentation:“RAISERROR 语句不支持 SET XACT_ABORT。新应用程序应使用 THROW 而不是 RAISERROR。" -
我知道这些程序是不现实的,我只是让它们找出并重现我在更复杂的查询中遇到的实际问题。外部过程仅将内部过程称为许多其他步骤之一,并且错误“自然”发生。我将在代码中指出它以提供进一步的清晰度。
-
不过,这些都不会改变我的观点,@Chris。外部程序将
ROLLBACKINSERT放入表dbo.LogTable;使INSERT毫无意义,并且您正在使用一个函数 (RAISERROR),该函数被专门记录为不尊重您正在使用的功能 (SET XACT_ABORT)。 -
我完全理解你的观点并且完全同意!一开始就是无意义的代码。我只是不明白为什么即使我没有提交我的事务也会抛出上述错误(无法提交当前事务)。使用
THROW而不是RAISEERROR不会改变行为。
标签: sql-server tsql error-handling transactions try-catch