我有两个过程,一个外部过程和一个内部过程,我想了解错误处理的行为。内部过程引发错误,并试图将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;
我想了解是什么让这个事务成为一个"注定要失败";事务,即使XACT_ABORT设置为关闭。
XACT_STATE()
是catch块中的-1
,因此事务注定要失败。
SELECT
CASE
WHEN 1 = 0
THEN 0.0
ELSE ''
END;
抛出错误
将数据类型varchar转换为numeric时出错。
"大多数转换错误";是Erland-Sommarskog将其归入错误类别的错误类型之一。
带回滚的批中止这是SQL Server最强烈的反应可能会导致用户错误。这些错误会中止对如果堆栈上没有CATCH处理程序并且它们也回滚任何未结交易。如果存在CATCH处理程序,则错误为捕获,但任何打开的事务都将注定并且必须回滚。行为是相同的,无论XACT_ABORT是ON还是OFF。
错误行为的分类有些神秘,没有记录,也不直观。阅读他的文章了解更多细节。