1
根據this,您可以在catch塊中擁有一個狀態,除非先回滾,否則無法執行任何寫入操作。不可承諾的事務可防止嵌套事務中的錯誤日誌
當您試圖處理嵌套事務並執行錯誤日誌記錄時,這是一個問題。在以下示例中,嵌套過程中的異常會丟失並且不記錄任何內容。
IF OBJECT_ID(N'dbo.ErrorLog', N'U') IS NOT NULL
DROP TABLE dbo.ErrorLog;
GO
CREATE TABLE dbo.ErrorLog (Error NVARCHAR(4000));
GO
IF OBJECT_ID(N'tempdb..#Caller') IS NOT NULL
BEGIN
DROP PROC#Caller;
END;
GO
CREATE PROCEDURE #Caller
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @transCount TINYINT = @@TRANCOUNT,
@returnCode INT,
@errorMessage NVARCHAR(4000),
@errorNumber INT;
BEGIN TRY
IF (@transCount = 0)
BEGIN
BEGIN TRAN;
END;
EXEC @returnCode = #Called;
IF (@returnCode <> 0)
BEGIN
RAISERROR(N'Error in Called. Caller returned an error', 16, -1);
END;
IF (@transCount = 0)
BEGIN
COMMIT TRAN;
END;
END TRY
BEGIN CATCH
IF ((@transCount = 0) AND (XACT_STATE() <> 0))
BEGIN
ROLLBACK TRAN;
END;
SELECT @errorMessage = ERROR_MESSAGE(),
@errorNumber = ERROR_NUMBER();
INSERT dbo.ErrorLog(Error) VALUES(@errorMessage); --only this logging happens
RAISERROR(N'Error in Caller.', 16, -1);
RETURN @errorNumber;
END CATCH;
RETURN;
END;
GO
IF OBJECT_ID(N'tempdb..#Called') IS NOT NULL
BEGIN
DROP PROC#Called;
END;
GO
CREATE PROC#Called
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @transCount TINYINT = @@TRANCOUNT,
@errorMessage NVARCHAR(4000),
@errorNumber INT;
BEGIN TRY
IF (@transCount = 0) --doesn't start tran, already in one
BEGIN
BEGIN TRAN;
END;
SELECT 1/0; --generate an error; this exception gets lost
IF (@transCount = 0)
BEGIN
COMMIT TRAN;
END;
END TRY
BEGIN CATCH
IF ((@transCount = 0) AND (XACT_STATE() <> 0)) --cannot rollback here because this didn't start the transaction
BEGIN
ROLLBACK TRAN;
END;
SELECT @errorMessage = ERROR_MESSAGE(),
@errorNumber = ERROR_NUMBER();
INSERT dbo.ErrorLog(Error) VALUES(@errorMessage); --doesn't happen because of uncommitable transaction; raises exception, caught in CATCH block of Caller
RAISERROR(N'Error in Called.', 16, -1); --this doesn't happen
RETURN @errorNumber; --nothing returned
END CATCH;
RETURN;
END
GO
EXEC dbo.#Caller;
GO
SELECT * FROM dbo.ErrorLog;
GO
記錄單錯誤只是uncommitable交易例外。有沒有辦法處理TRY..CATCH中的嵌套事務,還有實際發生的日誌錯誤?
我所知道的唯一的辦法就是因爲那些不受回滾使用表變量,但它可能會帶來麻煩,如果你的邏輯是複雜的。 –
不知道這會工作嘿。錯誤日誌應該是一個持久表。表變量在執行後會被清理乾淨。我也認爲一個表變量插入也不會在這裏工作,因爲它是一個寫操作,並且這些不允許在一個不可承諾的狀態。 – Knightwisp
寫入表變量必須在catch之外,或者至少我假設,並且在最終回滾之後將表變量寫入errorlog表。倖存的程序邊界可能會需要溫度。表或其他東西來傳輸數據。當然,如果錯誤只是一行,輸出參數應該可以工作。 –