根据this,你可以在catch块中有一个状态,除非你先回滚,否则你不能进行任何写操作。
当您尝试处理嵌套事务并执行错误记录时,这是一个问题。在以下示例中,嵌套过程中的异常会丢失,并且不会记录任何内容。
<form method="post" action="CreateServlet" name = "create">
Change Number(s):<br>
<input type="text" name="change" id="change">
<p></p>
<input type="submit" value="Download" onClick="return validateForm()">
</form>
<p></p>
<button id="send" name="send">Display</button>
记录的单个错误只是不可承受的事务异常。有没有办法在TRY..CATCH中处理嵌套事务,还是记录实际发生的错误?
答案 0 :(得分:0)
这种方法帮助我实现了我所需要的。基本上,在注定的tran(XACT_STATE()= -1)的情况下,整个事务被回滚以允许在两个级别上进行错误记录,同时在执行结束时仅引发一个异常。
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)) OR (XACT_STATE() = -1))
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)) OR (XACT_STATE() = -1)) --rollback even though didn't start this tran because its doomed
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
DECLARE @returnCode INT;
EXEC @returnCode = dbo.#Caller; --one exception raised
SELECT @returnCode AS 'returnCode'; --error code 50000 returned
SELECT * FROM dbo.ErrorLog; --both errors logged incl original exception