在我的存储过程中,我正在使用Try-Catch,并在Catch块中调用错误处理过程,该过程将在ErrorLog表中记录错误详细信息,然后重新抛出错误。
在我的C#代码中,我使用:
执行我的存储过程using(TransactionScope scope = new TransactionScope()) {
// execute stored procs
scope.Complete();
}
我遇到的问题,如果事务中止(从不调用scope.Complete),我的错误处理存储过程会重新抛出sql错误,但不能将错误记录到ErrorLog表中因为它是在交易的背景下;有没有办法解决 !?我已经知道当事务处于不可提交状态时无法插入数据,那么如何退出事务并仍然记录错误?
TSQL代码:
BEGIN PROCEDURE [dbo].[usp_UpsertSomething]
@SomethingID BIGINT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
-- do something
END TRY
BEGIN CATCH
EXEC dbo.cp_RethrowError
RETURN -1
END CATCH;
END
CREATE PROCEDURE [dbo].[usp_RethrowError]
@ErrorLogID [INT] = 0 OUTPUT -- Contains the ErrorLogID of the row inserted
-- by cp_RethrowError in the ErrorLog table.
AS
BEGIN
-- Return if there is no error information to retrieve.
IF ERROR_NUMBER() IS NULL
RETURN;
DECLARE
@ErrorMessage VARCHAR(4000),
@FormattedErrorMessage VARCHAR(4000),
@ErrorNumber INT,
@ErrorSeverity INT,
@ErrorState INT,
@ErrorLine INT,
@ErrorProcedure VARCHAR(200);
-- Assign variables to error-handling functions that
-- capture information for RAISERROR.
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
-- Build the message string that will contain original
-- error information.
SELECT @FormattedErrorMessage =
'ErrorLogID %d, Error %d, Level %d, State %d, Procedure %s, ' +
'Line %d, Message: '+ @ErrorMessage;
BEGIN TRY
-- Data insertion/modification is not allowed when
-- a transaction is in an uncommittable state.
IF XACT_STATE() = -1 BEGIN
SET @ErrorLogID = 0;
END
ELSE BEGIN
INSERT [dbo].[ErrorLog]
(
ErrorNumber,
ErrorSeverity,
ErrorState,
ErrorProcedure,
ErrorLine,
ErrorMessage
)
VALUES
(
@ErrorNumber,
@ErrorSeverity,
@ErrorState,
@ErrorProcedure,
@ErrorLine,
@ErrorMessage
);
-- Pass back the ErrorLogID of the row inserted
SELECT @ErrorLogID = @@IDENTITY;
END
END TRY
BEGIN CATCH
PRINT 'An error occurred in stored procedure cp_RethrowError.';
END CATCH
-- Raise an error: msg_str parameter of RAISERROR will contain
-- the original error information.
RAISERROR
(
@FormattedErrorMessage,
@ErrorSeverity,
1,
@ErrorLogID, -- parameter: ErrorLogID in ErrorLog table.
@ErrorNumber, -- parameter: original error number.
@ErrorSeverity, -- parameter: original error severity.
@ErrorState, -- parameter: original error state.
@ErrorProcedure, -- parameter: original error procedure name.
@ErrorLine -- parameter: original error line number.
);
END
答案 0 :(得分:0)
由于事务是一个全有或全无的交易,完成我想做的事情的唯一方法是在调用我的错误处理调用之前调用Catch块内的ROLLBACK TRANSACTION。
我的错误日志以我想要记录的错误结束,但在我的.Net catch块中,我最终得到了来自SQL的投诉:“EXECUTE之后的事务计数表明缺少COMMIT或ROLLBACK TRANSACTION语句。之前的计数= 1,当前计数= 0.“
我可以忍受!
答案 1 :(得分:0)
您还可以将错误日志条目放在表变量中(它应该与真实日志表具有相同的结构)。回滚不会清除表变量。最后,您只需将表变量的内容插入到真实的日志表中。
我没试过,但它可能会奏效。 SQL Server仍然缺少像自治事务这样的功能(Oracle已经拥有它)。无论您在自主交易中做什么都独立于主要交易。这正是错误记录时所需要的:特别是在回滚事务时,您仍然想知道发生了什么。
答案 2 :(得分:0)
这是一个排序问题。检查错误处理程序中的事务计数。 脚步: 1.首先将原始错误信息输入@variables或@table。 2.检查您的交易计数,如果它大于0,则将其回滚。 3.插入您在步骤1中收集的错误信息。 结束。