【问题标题】:how to write a t-sql program to catch transaction raised error at the very end如何编写一个 t-sql 程序以在最后捕获事务引发的错误
【发布时间】:2015-11-04 00:33:18
【问题描述】:

我是 T-SQL 编程的新手。我需要编写一个主要程序来执行多个事务。我如何构建程序以使每个事务都不会中止。相反,在所有事务完成运行后,该过程将引发错误并在输出参数中将它们报告回主程序。如果可以的话,请给我提供伪代码。谢谢。

【问题讨论】:

  • 嗨@TaroYuki,你自己写过代码吗?你应该发布它

标签: sql-server tsql


【解决方案1】:

您需要遵循Exception handling and nested transactions的模板

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end
go

如您所见,您不能总是继续,因为有时异常在您捕获它时已经中止了事务(典型示例是死锁异常 1205)。并且您必须使用保存点并在出现异常时恢复到保存点,以保持数据库的一致性。但是,如果可能,请不要中止调用者的工作。

【讨论】:

    【解决方案2】:

    你可以使用 try/catch

    BOL - TRY/CATCH

    Here's an example

    我之前已经将逻辑封装到存储过程中,并在 TRY/CATCH 块中放入了 exec 语句。在 CATCH 中您可以使用此链接获取错误信息(链接中的示例 B)

    BOL - ERROR_MESSAGE

    类似于 -

    BEGIN TRY
        BEGIN TRAN
        EXEC StoredProcedure01
        EXEC StoredProcedure02
        COMMIT
    END TRY
    BEGIN CATCH
        ROLLBACK TRAN
        SELECT
            ERROR_NUMBER() AS ErrorNumber
            ,ERROR_SEVERITY() AS ErrorSeverity
            ,ERROR_STATE() AS ErrorState
            ,ERROR_PROCEDURE() AS ErrorProcedure
            ,ERROR_LINE() AS ErrorLine
            ,ERROR_MESSAGE() AS ErrorMessage;
    END CATCH;
    GO
    

    【讨论】:

      【解决方案3】:

      我可能会考虑试试这个。每个事务都是一个单独的存储过程,具有一个整体存储过程,依次调用每个事务。将所需的错误信息保存在表变量中。在每个 proc 的 catch 块中,回滚该事务,然后将带有错误信息的表变量中的数据插入到日志表中。不要将失败返回给调用过程。

      如果您想实时报告主进程外的错误,您可以在最后从日志表中进行选择。

      如果您在调用 proc 的开头创建一个 batchid 并将其作为您调用的每个 procs 的输入变量并将该数据包含在您添加到日志记录表的信息中,则效果最好。然后,如果 proc 在非工作时间多次失败,您就会看到所有错误,并且可以看到它们关联的批次。这极大地有助于追踪问题。

      在设计日志记录表时,您需要考虑一下您需要为每个 proc 提供哪些信息。我建议您存储的部分内容是发送到 proc 的任何输入变量。此外,如果您使用的是动态 SQl,则还要存储生成的 sql。如果您可以识别运行 proc 的用户,那么这对于跟踪权限问题也很有用。

      拥有一个日志表比仅仅在运行时返回错误有用得多。您可以查看趋势,查看是否经常发生相同的错误,查看导致失败的信息以及成功的信息(如果您选择同时记录成功运行的变量)。

      所有这些都不是开箱即用的易于编写的代码。它需要您进行大量的设计来确定,随着时间的推移,哪些信息将有助于解决流程问题。您需要获得的详细信息是基于数据的使用方式以及您希望了解的有关故障的信息的业务决策。因此,我们无法为您做出此决定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-27
        • 1970-01-01
        • 2023-03-27
        • 1970-01-01
        相关资源
        最近更新 更多