sql server:插入事务中的表以记录错误发生?

发布于 2024-11-14 22:19:23 字数 632 浏览 2 评论 0原文

我有一个 SP(存储过程),其中包含一些 T-SQL 语句......

所有 T-sql 语句都在事务块中,并且通过发生任何错误,我都会回滚所有内容。

像这样:

BEGIN TRANSACTION
.....
.....
IF @X=1
BEGIN
    declare cu cursor for select col1,col2 from Table1 where Id=@Y
    open  cu
    fetch next from cuinto @A, @B
    while  @@Fetch_Status = 0
    BEGIN
         .....
        ......
        IF @@ERROR <>0
        BEGIN
            ROLLBACK TRANSACTION
            RETURN
        END
END
.....
.....

Sp 无法正常运行,我找不到它的 reean 是什么...... 我认为通过将一些数据插入表中来记录 sp 中的每个操作是个好主意 我的问题是:

因为它使用事务,所以每次插入都会回滚......

您的意见是什么?还有其他办法吗?

谢谢

I have a SP (Stored procedure) which is contained of some T-SQL statements.....

All of T-sql statements are in a transaction block and by occuring any error, I rollback every thing.

like this:

BEGIN TRANSACTION
.....
.....
IF @X=1
BEGIN
    declare cu cursor for select col1,col2 from Table1 where Id=@Y
    open  cu
    fetch next from cuinto @A, @B
    while  @@Fetch_Status = 0
    BEGIN
         .....
        ......
        IF @@ERROR <>0
        BEGIN
            ROLLBACK TRANSACTION
            RETURN
        END
END
.....
.....

The Sp does not run properly and I can't find what the resean of it is.....
I think it's a good idea to log every operation within sp by inserting some data into a table
My Question is:

Because it uses a transaction, every insertion will be rolled back.....

What's your opinion? Is there any other way?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

左耳近心 2024-11-21 22:19:23

3 件事:
1)如果没有必要,请不要使用光标。
2) 您可以使用 RAISERROR WITH LOG将数据插入表变量,然后将其插入到真实的表中您已回滚您的交易。这是可能的,因为表变量是独立于事务的。
3) 使用 try catch

3 things:
1) please, please don't use cursors if you don't have to.
2) you can log by using either RAISERROR WITH LOG or by inserting data into a table variable and then inserting that into a real table after you've rolledback your transaction. This is possible because table variables are transaction independent.
3) Use the try catch block

你怎么这么可爱啊 2024-11-21 22:19:23

现在没有理由使用@@ERROR:TRY/CATCH 更加可靠。要了解更多信息,我建议阅读 Erland Sommarskog 的 “SQL 2005 及更高版本中的错误处理”,它是一篇关于该主题的权威文章

在这种情况下,如果没有 TRY/CATCH,某些错误将被批量中止:这意味着代码将停止并且不会捕获任何错误。除编译错误外,此问题已通过 TRY/CATCH 修复。

该模板取自我之前的答案嵌套存储过程包含尝试捕获回滚模式?

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
    -- if desired INSERT ExceptionLogTable () .. 
END CATCH
GO

如果您使用 SET XACT_ABORT ON (我认为这应该是最佳实践),那么在任何CATCH 块 @@trancount 为零。因此,如果您愿意,除了抛出错误之外,还可以在此处写入日志表。

There is no reason to use @@ERROR now: TRY/CATCH is far more reliable. To understand more then I recommend reading Erland Sommarskog's "Error Handling in SQL 2005 and Later" which is one the definitive articles on the subject

In this case, without TRY/CATCH, some errors are batch aborting: this means the code stops and no error is trapped. This is fixed with TRY/CATCH except for compile errors.

This template is taken from my previous answer Nested stored procedures containing TRY CATCH ROLLBACK pattern?

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
    -- if desired INSERT ExceptionLogTable () .. 
END CATCH
GO

If you use SET XACT_ABORT ON (which I reckon should be best practice), then in any CATCH block @@trancount is zero. So you can write into a logging table here if you wish, in addition to throwing an error.

七秒鱼° 2024-11-21 22:19:23

我重写了您的代码,通过使用 TransactionTry Catch

CREATE PROCEDURE [dbo].[mySP] 
(
    @X int, @Y int,
    @Return_Message VARCHAR(1024) = ''  OUT
)
AS

    SET NOCOUNT ON;

    Declare @A varchar(100) @B varchar(100)

BEGIN TRY

    BEGIN TRAN

        IF @X=1
        BEGIN
            declare cu cursor for select col1,col2 from Table1 where Id=@Y
            open  cu
            fetch next from cu into @A, @B
            while  @@Fetch_Status = 0
            BEGIN
                -- .....
                -- do your stuff
                FETCH NEXT FROM cu into @A, @B              
            END
        END

    COMMIT TRAN

    SELECT  @Return_Message = 'All OK'

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN 1   -- success

END TRY

BEGIN CATCH
    /*************************************
    *  if errors rollback
    *************************************/
    IF @@TRANCOUNT > 0 ROLLBACK

    SELECT @Return_Message = @ErrorStep + ' '
        + cast(ERROR_NUMBER() as varchar(20)) + ' line: '
        + cast(ERROR_LINE() as varchar(20)) + ' ' 
        + ERROR_MESSAGE() + ' > ' 
        + ERROR_PROCEDURE()

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN 0   -- fail

END CATCH

SP 用法:为您提供一个真实的示例

declare @ret int, @Return_Message VARCHAR(1024)

EXEC @ret = mySP 1, 2, @Return_Message OUTPUT

-- the SP Fail so print or store the return message with errors ...
if @ret = 0 print @Return_Message

I rewrote your code to give you a real example by using the Transaction and Try Catch

CREATE PROCEDURE [dbo].[mySP] 
(
    @X int, @Y int,
    @Return_Message VARCHAR(1024) = ''  OUT
)
AS

    SET NOCOUNT ON;

    Declare @A varchar(100) @B varchar(100)

BEGIN TRY

    BEGIN TRAN

        IF @X=1
        BEGIN
            declare cu cursor for select col1,col2 from Table1 where Id=@Y
            open  cu
            fetch next from cu into @A, @B
            while  @@Fetch_Status = 0
            BEGIN
                -- .....
                -- do your stuff
                FETCH NEXT FROM cu into @A, @B              
            END
        END

    COMMIT TRAN

    SELECT  @Return_Message = 'All OK'

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN 1   -- success

END TRY

BEGIN CATCH
    /*************************************
    *  if errors rollback
    *************************************/
    IF @@TRANCOUNT > 0 ROLLBACK

    SELECT @Return_Message = @ErrorStep + ' '
        + cast(ERROR_NUMBER() as varchar(20)) + ' line: '
        + cast(ERROR_LINE() as varchar(20)) + ' ' 
        + ERROR_MESSAGE() + ' > ' 
        + ERROR_PROCEDURE()

    /*************************************
    *  Return from the Stored Procedure
    *************************************/
    RETURN 0   -- fail

END CATCH

SP Usage:

declare @ret int, @Return_Message VARCHAR(1024)

EXEC @ret = mySP 1, 2, @Return_Message OUTPUT

-- the SP Fail so print or store the return message with errors ...
if @ret = 0 print @Return_Message
高速公鹿 2024-11-21 22:19:23

您还可以使用异常处理来实现href="http://www.sqlservercentral.com/articles/news/exceptionhandlinginsqlserver2005/2237/" rel="nofollow">尝试也抓住

Begin Try
    BEGIN TRANSACTION
.....
.....
IF @X=1
BEGIN
    declare cu cursor for select col1,col2 from Table1 where Id=@Y
    open  cu
    fetch next from cuinto @A, @B
    while  @@Fetch_Status = 0
    BEGIN
        .....
        ......
        //Your insert statement....
END
.....
.....
Commit Tran

End Try

Begin Catch
      Rollback Tran
      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

You can also implement Exception Handling using Try Catch as well

Begin Try
    BEGIN TRANSACTION
.....
.....
IF @X=1
BEGIN
    declare cu cursor for select col1,col2 from Table1 where Id=@Y
    open  cu
    fetch next from cuinto @A, @B
    while  @@Fetch_Status = 0
    BEGIN
        .....
        ......
        //Your insert statement....
END
.....
.....
Commit Tran

End Try

Begin Catch
      Rollback Tran
      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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文