Sql server 在SQL Server 2005数据库中记录存储过程错误

Sql server 在SQL Server 2005数据库中记录存储过程错误,sql-server,tsql,Sql Server,Tsql,我正在为我的TSQL存储过程使用下面所示的通用构造。这对于将错误信息返回到调用应用程序代码非常有效。但是,我也希望将错误记录在数据库本身中。如何在SQLServer2005中实现这一点 BEGIN TRY TSQL... END TRY BEGIN CATCH DECLARE @ErrorMessage NVARCHAR(4000) DECLARE @ErrorSeverity INT DECLARE @ErrorState INT SELECT @ErrorMessage = ERR

我正在为我的TSQL存储过程使用下面所示的通用构造。这对于将错误信息返回到调用应用程序代码非常有效。但是,我也希望将错误记录在数据库本身中。如何在SQLServer2005中实现这一点

BEGIN TRY

TSQL...

END TRY
BEGIN CATCH 
DECLARE @ErrorMessage NVARCHAR(4000)
DECLARE @ErrorSeverity INT
DECLARE @ErrorState INT

SELECT  @ErrorMessage = ERROR_MESSAGE(),
    @ErrorSeverity = ERROR_SEVERITY(),
    @ErrorState = ERROR_STATE()

-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR ( @ErrorMessage, -- Message text.
    @ErrorSeverity, -- Severity.
    @ErrorState -- State.
       )
END CATCH

SET NOCOUNT OFF
SET @Error = @@ERROR
RETURN @Error

创建一个包含列(MessageText、Severity、State、DateTimeOccessed)的错误表,并将信息插入其中。

创建一个包含列(MessageText、Severity、State、DateTimeOccessed)的错误表然后
将信息插入其中。

创建一个错误日志表,并将其写入CATCH块中

但这并不是那么容易

但是,您需要先测试“@@TRANCOUNT=0”,因为它将在以后回滚,例如您是否使用TRY/CATCH嵌套存储过程或是否有客户端事务。如果使用
SET XACT\u ABORT ON


这意味着如果有嵌套,可能会有多条错误消息,因此我还要记录
error\u PROCEDURE()
OBJECT\u NAME(@@PROCID)
,以区分错误发生的位置和记录的位置

创建一个ErrorLog表,并将其写入CATCH块中

但这并不是那么容易

但是,您需要先测试“@@TRANCOUNT=0”,因为它将在以后回滚,例如您是否使用TRY/CATCH嵌套存储过程或是否有客户端事务。如果使用
SET XACT\u ABORT ON


这意味着如果有嵌套,可能会有多条错误消息,因此我还要记录
error\u PROCEDURE()
OBJECT\u NAME(@@PROCID)
,以区分错误发生的位置和记录的位置

简单的答案是“写入日志表”,但实际上这有点复杂,因为您所做的任何表写入都受当前事务的影响,而catch块受错误处理三态事务的影响。您必须使用来检查当前事务状态。如果是一个注定失败的事务(状态-1),则必须首先回滚,然后记录,否则尝试插入日志表将导致批处理中止


有关使用T-SQL try/catch块并正确处理事务的过程模板的示例,请参见。

简单的答案是“写入日志表”,但实际上这有点复杂,因为您所做的任何表写入都受当前事务的约束,而catch块受错误处理三态事务的约束。您必须使用来检查当前事务状态。如果是一个注定失败的事务(状态-1),则必须首先回滚,然后记录,否则尝试插入日志表将导致批处理中止


有关使用T-SQL try/catch块并正确处理事务的过程模板的示例,请参阅。

这里是一个带有回滚的嵌套过程日志记录示例

这将创建两个测试表和三个过程,可以通过事务以嵌套方式调用它们:

if exists (select * from sysobjects where id = object_id(N'[dbo].ProcedureA') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [dbo].ProcedureA
if exists (select * from sysobjects where id = object_id(N'[dbo].ProcedureB') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [dbo].ProcedureB
if exists (select * from sysobjects where id = object_id(N'[dbo].ProcedureC') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [dbo].ProcedureC
if exists (select * from sysobjects where id = object_id(N'YourLogTable') and OBJECTPROPERTY(id, N'IsTable') = 1) drop table YourLogTable
if exists (select * from sysobjects where id = object_id(N'YourTestTable') and OBJECTPROPERTY(id, N'IsTable') = 1) drop table YourTestTable

go
CREATE TABLE YourLogTable
(
     LogID    int               not null primary key identity(1,1)
    ,LogDate  datetime          not null default GETDATE()
    ,ProcedureName varchar(50)  null default OBJECT_NAME(@@PROCID)
    ,LogText varchar(8000)      not null
)
go
CREATE TABLE YourTestTable
(
     TestID    int not null primary key identity(1,1)
    ,TestData  varchar(100) not null
)

go
-----------------------------------------------------------------------
-----------------------------------------------------------------------
CREATE PROCEDURE ProcedureA
(
    @ParamA1     int
   ,@ParamA2     varchar(10)
   ,@ErrorMsg    varchar(1000) OUTPUT
)
AS

DECLARE @LogValue      varchar(8000)
DECLARE @ReturnValueX  int
DECLARE @ErrorMsgX     varchar(1000)

DECLARE @TempValue     int

BEGIN TRY

    SET @LogValue=ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
        +': @ParamA1='+COALESCE(''''+CONVERT(varchar(10),@ParamA1)+'''','null')
        +', @ParamA2='+COALESCE(''''+@ParamA2+'''','null')


    BEGIN TRANSACTION --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,

    INSERT INTO YourTestTable (TestData) VALUES ('I was in top of ProdecureA')



    --your logic logic here---
    IF @ParamA1=1
    BEGIN
        RAISERROR('testing, bad parameter',16,1) --send control to the BEGIN CATCH block
    END

    SET @TempValue=@ParamA1/@ParamA1

    EXEC @ReturnValueX=ProcedureB @ParamA1,@ParamA2,@ErrorMsgX OUTPUT
    IF @ReturnValueX!=0
    BEGIN
        SET @ErrorMsg='Call to ProcedureB failed, ReturnValueX='+COALESCE(''''+CONVERT(varchar(10),@ReturnValueX)+'''','null')+', @ErrorMsgX='+COALESCE(''''+CONVERT(varchar(10),@ErrorMsgX)+'''','null')
        RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block
    END

    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in bottom of ProdecureA')


END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @ErrorMsg=@LogValue+'; '
                   +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                   +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                   +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                   +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                   +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                   +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END
    INSERT INTO YourLogTable (LogText) VALUES (@ErrorMsg)
    RETURN 999

END CATCH

IF XACT_STATE()!=0
BEGIN
    COMMIT
END

--PRINT ISNULL(OBJECT_NAME(@@PROCID), 'unknown')+' OK'
RETURN 0
GO

-----------------------------------------------------------------------
-----------------------------------------------------------------------
CREATE PROCEDURE ProcedureB
(
    @ParamB1     int
   ,@ParamB2     varchar(10)
   ,@ErrorMsg    varchar(1000) OUTPUT
)
AS

DECLARE @LogValue      varchar(8000)
DECLARE @ReturnValueX  int
DECLARE @ErrorMsgX     varchar(1000)

DECLARE @TempValue     int

BEGIN TRY

    SET @LogValue=ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
        +': @ParamB1='+COALESCE(''''+CONVERT(varchar(10),@ParamB1)+'''','null')
        +', @ParamB2='+COALESCE(''''+@ParamB2+'''','null')

    BEGIN TRANSACTION --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,

    INSERT INTO YourTestTable (TestData) VALUES ('I was in top of ProdecureB')

    --your logic logic here---
    IF @ParamB1=10
    BEGIN
        RAISERROR('testing, bad parameter',16,1) --send control to the BEGIN CATCH block
    END

    SET @TempValue=@ParamB1/@ParamB1

    EXEC @ReturnValueX=ProcedureC @ParamB1,@ErrorMsgX OUTPUT
    IF @ReturnValueX!=0
    BEGIN
        SET @ErrorMsg='Call to ProcedureC failed, ReturnValueX='+COALESCE(''''+CONVERT(varchar(10),@ReturnValueX)+'''','null')+', @ErrorMsgX='+COALESCE(''''+CONVERT(varchar(10),@ErrorMsgX)+'''','null')
        RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block
    END

    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in bottom of ProdecureB')


END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @ErrorMsg=@LogValue+'; '
                   +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                   +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                   +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                   +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                   +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                   +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END
    INSERT INTO YourLogTable (LogText) VALUES (@ErrorMsg)

    RETURN 999

END CATCH

IF XACT_STATE()!=0
BEGIN
    COMMIT
END
--PRINT ISNULL(OBJECT_NAME(@@PROCID), 'unknown')+' OK'
RETURN 0
GO

-----------------------------------------------------------------------
-----------------------------------------------------------------------
CREATE PROCEDURE ProcedureC
(
    @ParamC1     int
   ,@ErrorMsg    varchar(1000) OUTPUT
)
AS

DECLARE @LogValue      varchar(8000)
DECLARE @ReturnValueX  int
DECLARE @ErrorMsgX     varchar(1000)

DECLARE @TempValue     int


BEGIN TRY

    BEGIN TRANSACTION --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,

    SET @LogValue=ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
        +': @ParamC1='+COALESCE(''''+CONVERT(varchar(10),@ParamC1)+'''','null')

    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in top of ProdecureC')

    IF @ParamC1=100
    BEGIN
        RAISERROR('testing, bad parameter',16,1) --send control to the BEGIN CATCH block
    END

    SET @TempValue=@ParamC1/@ParamC1


    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in bottom of ProdecureC')


END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @ErrorMsg=@LogValue+'; '
                   +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                   +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                   +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                   +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                   +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                   +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END
    INSERT INTO YourLogTable (LogText) VALUES (@ErrorMsg)

    RETURN 999

END CATCH

IF XACT_STATE()!=0
BEGIN
    COMMIT
END
--PRINT ISNULL(OBJECT_NAME(@@PROCID), 'unknown')+' OK'
RETURN 0
GO
以下是输出,它在日志中显示了一个堆栈,尽管有回滚:

###########################################################################
will error out in A - should log A>>> EXEC ProcedureA 1,'abcd'

(6 row(s) affected)

(0 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
@ReturnValue @ErrorMsg
------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
999          ProcedureA: @ParamA1='1', @ParamA2='abcd'; Msg 50000, Level 16, State 1, Procedure ProcedureA, Line 33, testing, bad parameter

(1 row(s) affected)

YourTestTable TestID      TestData
------------- ----------- ----------------------------------------------------------------------------------------------------

(0 row(s) affected)

YourLogTable LogID       LogDate                 ProcedureName                                      LogText
------------ ----------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
YourLogTable 37          2009-09-08 15:04:39.663 ProcedureA                                         ProcedureA: @ParamA1='1', @ParamA2='abcd'; Msg 50000, Level 16, State 1, Procedure ProcedureA, Line 33, testing, bad parameter

(1 row(s) affected)

###########################################################################
will error out in B - should log B and A>>> EXEC ProcedureA 10,'abcd'

(0 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
@ReturnValue @ErrorMsg
------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
999          ProcedureA: @ParamA1='10', @ParamA2='abcd'; Msg 266, Level 16, State 2, Procedure ProcedureB, Line 0, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

(1 row(s) affected)

YourTestTable TestID      TestData
------------- ----------- ----------------------------------------------------------------------------------------------------

(0 row(s) affected)

YourLogTable LogID       LogDate                 ProcedureName                                      LogText
------------ ----------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
YourLogTable 38          2009-09-08 15:04:39.680 ProcedureB                                         ProcedureB: @ParamB1='10', @ParamB2='abcd'; Msg 50000, Level 16, State 1, Procedure ProcedureB, Line 31, testing, bad parameter
YourLogTable 39          2009-09-08 15:04:39.680 ProcedureA                                         ProcedureA: @ParamA1='10', @ParamA2='abcd'; Msg 266, Level 16, State 2, Procedure ProcedureB, Line 0, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

(2 row(s) affected)

###########################################################################
will error out in C - should log C, B and A>>>> EXEC ProcedureA 100,'123'

(0 row(s) affected)

(2 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
@ReturnValue @ErrorMsg
------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
999          ProcedureA: @ParamA1='100', @ParamA2='123'; Msg 266, Level 16, State 2, Procedure ProcedureB, Line 0, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

(1 row(s) affected)

YourTestTable TestID      TestData
------------- ----------- ----------------------------------------------------------------------------------------------------

(0 row(s) affected)

YourLogTable LogID       LogDate                 ProcedureName                                      LogText
------------ ----------- ----------------------- -------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面是一个带有回滚的嵌套过程日志的示例

这将创建两个测试表和三个过程,可以通过事务以嵌套方式调用它们:

if exists (select * from sysobjects where id = object_id(N'[dbo].ProcedureA') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [dbo].ProcedureA
if exists (select * from sysobjects where id = object_id(N'[dbo].ProcedureB') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [dbo].ProcedureB
if exists (select * from sysobjects where id = object_id(N'[dbo].ProcedureC') and OBJECTPROPERTY(id, N'IsProcedure') = 1) drop procedure [dbo].ProcedureC
if exists (select * from sysobjects where id = object_id(N'YourLogTable') and OBJECTPROPERTY(id, N'IsTable') = 1) drop table YourLogTable
if exists (select * from sysobjects where id = object_id(N'YourTestTable') and OBJECTPROPERTY(id, N'IsTable') = 1) drop table YourTestTable

go
CREATE TABLE YourLogTable
(
     LogID    int               not null primary key identity(1,1)
    ,LogDate  datetime          not null default GETDATE()
    ,ProcedureName varchar(50)  null default OBJECT_NAME(@@PROCID)
    ,LogText varchar(8000)      not null
)
go
CREATE TABLE YourTestTable
(
     TestID    int not null primary key identity(1,1)
    ,TestData  varchar(100) not null
)

go
-----------------------------------------------------------------------
-----------------------------------------------------------------------
CREATE PROCEDURE ProcedureA
(
    @ParamA1     int
   ,@ParamA2     varchar(10)
   ,@ErrorMsg    varchar(1000) OUTPUT
)
AS

DECLARE @LogValue      varchar(8000)
DECLARE @ReturnValueX  int
DECLARE @ErrorMsgX     varchar(1000)

DECLARE @TempValue     int

BEGIN TRY

    SET @LogValue=ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
        +': @ParamA1='+COALESCE(''''+CONVERT(varchar(10),@ParamA1)+'''','null')
        +', @ParamA2='+COALESCE(''''+@ParamA2+'''','null')


    BEGIN TRANSACTION --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,

    INSERT INTO YourTestTable (TestData) VALUES ('I was in top of ProdecureA')



    --your logic logic here---
    IF @ParamA1=1
    BEGIN
        RAISERROR('testing, bad parameter',16,1) --send control to the BEGIN CATCH block
    END

    SET @TempValue=@ParamA1/@ParamA1

    EXEC @ReturnValueX=ProcedureB @ParamA1,@ParamA2,@ErrorMsgX OUTPUT
    IF @ReturnValueX!=0
    BEGIN
        SET @ErrorMsg='Call to ProcedureB failed, ReturnValueX='+COALESCE(''''+CONVERT(varchar(10),@ReturnValueX)+'''','null')+', @ErrorMsgX='+COALESCE(''''+CONVERT(varchar(10),@ErrorMsgX)+'''','null')
        RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block
    END

    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in bottom of ProdecureA')


END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @ErrorMsg=@LogValue+'; '
                   +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                   +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                   +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                   +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                   +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                   +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END
    INSERT INTO YourLogTable (LogText) VALUES (@ErrorMsg)
    RETURN 999

END CATCH

IF XACT_STATE()!=0
BEGIN
    COMMIT
END

--PRINT ISNULL(OBJECT_NAME(@@PROCID), 'unknown')+' OK'
RETURN 0
GO

-----------------------------------------------------------------------
-----------------------------------------------------------------------
CREATE PROCEDURE ProcedureB
(
    @ParamB1     int
   ,@ParamB2     varchar(10)
   ,@ErrorMsg    varchar(1000) OUTPUT
)
AS

DECLARE @LogValue      varchar(8000)
DECLARE @ReturnValueX  int
DECLARE @ErrorMsgX     varchar(1000)

DECLARE @TempValue     int

BEGIN TRY

    SET @LogValue=ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
        +': @ParamB1='+COALESCE(''''+CONVERT(varchar(10),@ParamB1)+'''','null')
        +', @ParamB2='+COALESCE(''''+@ParamB2+'''','null')

    BEGIN TRANSACTION --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,

    INSERT INTO YourTestTable (TestData) VALUES ('I was in top of ProdecureB')

    --your logic logic here---
    IF @ParamB1=10
    BEGIN
        RAISERROR('testing, bad parameter',16,1) --send control to the BEGIN CATCH block
    END

    SET @TempValue=@ParamB1/@ParamB1

    EXEC @ReturnValueX=ProcedureC @ParamB1,@ErrorMsgX OUTPUT
    IF @ReturnValueX!=0
    BEGIN
        SET @ErrorMsg='Call to ProcedureC failed, ReturnValueX='+COALESCE(''''+CONVERT(varchar(10),@ReturnValueX)+'''','null')+', @ErrorMsgX='+COALESCE(''''+CONVERT(varchar(10),@ErrorMsgX)+'''','null')
        RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block
    END

    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in bottom of ProdecureB')


END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @ErrorMsg=@LogValue+'; '
                   +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                   +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                   +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                   +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                   +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                   +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END
    INSERT INTO YourLogTable (LogText) VALUES (@ErrorMsg)

    RETURN 999

END CATCH

IF XACT_STATE()!=0
BEGIN
    COMMIT
END
--PRINT ISNULL(OBJECT_NAME(@@PROCID), 'unknown')+' OK'
RETURN 0
GO

-----------------------------------------------------------------------
-----------------------------------------------------------------------
CREATE PROCEDURE ProcedureC
(
    @ParamC1     int
   ,@ErrorMsg    varchar(1000) OUTPUT
)
AS

DECLARE @LogValue      varchar(8000)
DECLARE @ReturnValueX  int
DECLARE @ErrorMsgX     varchar(1000)

DECLARE @TempValue     int


BEGIN TRY

    BEGIN TRANSACTION --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,

    SET @LogValue=ISNULL(OBJECT_NAME(@@PROCID), 'unknown')
        +': @ParamC1='+COALESCE(''''+CONVERT(varchar(10),@ParamC1)+'''','null')

    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in top of ProdecureC')

    IF @ParamC1=100
    BEGIN
        RAISERROR('testing, bad parameter',16,1) --send control to the BEGIN CATCH block
    END

    SET @TempValue=@ParamC1/@ParamC1


    --your logic logic here---
    INSERT INTO YourTestTable (TestData) VALUES ('I was in bottom of ProdecureC')


END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @ErrorMsg=@LogValue+'; '
                   +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                   +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                   +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                   +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                   +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                   +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END
    INSERT INTO YourLogTable (LogText) VALUES (@ErrorMsg)

    RETURN 999

END CATCH

IF XACT_STATE()!=0
BEGIN
    COMMIT
END
--PRINT ISNULL(OBJECT_NAME(@@PROCID), 'unknown')+' OK'
RETURN 0
GO
以下是输出,它在日志中显示了一个堆栈,尽管有回滚:

###########################################################################
will error out in A - should log A>>> EXEC ProcedureA 1,'abcd'

(6 row(s) affected)

(0 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
@ReturnValue @ErrorMsg
------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
999          ProcedureA: @ParamA1='1', @ParamA2='abcd'; Msg 50000, Level 16, State 1, Procedure ProcedureA, Line 33, testing, bad parameter

(1 row(s) affected)

YourTestTable TestID      TestData
------------- ----------- ----------------------------------------------------------------------------------------------------

(0 row(s) affected)

YourLogTable LogID       LogDate                 ProcedureName                                      LogText
------------ ----------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
YourLogTable 37          2009-09-08 15:04:39.663 ProcedureA                                         ProcedureA: @ParamA1='1', @ParamA2='abcd'; Msg 50000, Level 16, State 1, Procedure ProcedureA, Line 33, testing, bad parameter

(1 row(s) affected)

###########################################################################
will error out in B - should log B and A>>> EXEC ProcedureA 10,'abcd'

(0 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
@ReturnValue @ErrorMsg
------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
999          ProcedureA: @ParamA1='10', @ParamA2='abcd'; Msg 266, Level 16, State 2, Procedure ProcedureB, Line 0, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

(1 row(s) affected)

YourTestTable TestID      TestData
------------- ----------- ----------------------------------------------------------------------------------------------------

(0 row(s) affected)

YourLogTable LogID       LogDate                 ProcedureName                                      LogText
------------ ----------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
YourLogTable 38          2009-09-08 15:04:39.680 ProcedureB                                         ProcedureB: @ParamB1='10', @ParamB2='abcd'; Msg 50000, Level 16, State 1, Procedure ProcedureB, Line 31, testing, bad parameter
YourLogTable 39          2009-09-08 15:04:39.680 ProcedureA                                         ProcedureA: @ParamA1='10', @ParamA2='abcd'; Msg 266, Level 16, State 2, Procedure ProcedureB, Line 0, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

(2 row(s) affected)

###########################################################################
will error out in C - should log C, B and A>>>> EXEC ProcedureA 100,'123'

(0 row(s) affected)

(2 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
@ReturnValue @ErrorMsg
------------ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
999          ProcedureA: @ParamA1='100', @ParamA2='123'; Msg 266, Level 16, State 2, Procedure ProcedureB, Line 0, Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

(1 row(s) affected)

YourTestTable TestID      TestData
------------- ----------- ----------------------------------------------------------------------------------------------------

(0 row(s) affected)

YourLogTable LogID       LogDate                 ProcedureName                                      LogText
------------ ----------- ----------------------- -------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

从长远来看,混合的try-catch逻辑和返回错误代码是行不通的。可以保证,有人会忘记检查过程返回代码,并依靠calee回滚的事务的存在向前推进!可以说,通过使用保存点,单独依赖异常并正确处理XACT_状态的所有3种状态要好得多,从而允许调用方决定在发生错误时是回滚还是继续使用备用路径。许多错误是可以恢复的。谢谢你提供了这样一个完整的例子@Remus Rusanu,我们从不使用保存点,总是回滚,因此调用方几乎没有选项,因为事务计数不匹配,它将自动转到捕获。混合的try-catch逻辑和返回错误代码从长远来看是不起作用的。可以保证,有人会忘记检查过程返回代码,并依靠calee回滚的事务的存在向前推进!可以说,通过使用保存点,单独依赖异常并正确处理XACT_状态的所有3种状态要好得多,从而允许调用方决定在发生错误时是回滚还是继续使用备用路径。许多错误是可以恢复的。谢谢你提供了这样一个完整的例子@Remus Rusanu,我们从不使用保存点,总是回滚,因此调用方几乎没有选项,因为事务计数不匹配,它将自动转到捕获。