开发者

Exit and rollback everything in script on error

I have a TSQL script that does a lot of database structure adjustments but it's not really safe to just let it go through when something fails.

to make things clear:

  • using MS SQL 2005
  • it's NOT a stored procedure, just a script file (.sql)

what I have is something in the following order

BEGIN TRANSACTION
    ALTER Stuff
    GO

    CREATE New Stuff
    GO

    DROP Old Stuff
    GO
IF @@ERROR != 0
    BEGIN
  PRINT 'Errors Found ... Rolling back'
  ROLLBACK TRANSACTION
  RETURN
    END
ELSE
     PRINT 'No Errors ... Committing changes'
     COMMIT TRANSACTION

just to illustrate what I'm working with ... can't go into specifics now, the problem ...

When I introduce an error (to test if things get rolled back), I get a statement that the ROLLBACK TRANSACTION could not find a corresponding BEGIN TRANSACTION. This leads me to believe that something when REALLY wrong and the transaction was already killed. what I also noticed is that the script didn't fully quit on erro开发者_开发技巧r and thus DID try to execute every statement after the error occured. (I noticed this when new tables showed up when I wasn't expecting them because it should have rollbacked)


When the error occurs, the transaction is rolled back automatically, and the current batch is aborted.

Execution continues into the next batch, however. So all the stuff in the batches after the error gets executed. And then when you check for errors later, you try to rollback an already rolled back transaction.

Also, to stop the entire script, not just the current batch, you should use:

raiserror('Error description here', 20, -1) with log

See my answer here for details on that one.

So you need to check for @error after each batch, I think something like this should work:

BEGIN TRANSACTION
GO

ALTER Stuff
GO

if @@error != 0 raiserror('Script failed', 20, -1) with log
GO

CREATE New Stuff
GO

if @@error != 0 raiserror('Script failed', 20, -1) with log
GO

DROP Old Stuff
GO

if @@error != 0 raiserror('Script failed', 20, -1) with log
GO

PRINT 'No Errors ... Committing changes'
COMMIT TRANSACTION


Try using RETURN. this will exit the script or procedure immediately and will not execute any of the following statements. You can use this in conjunction with BEGIN, ROLLBACK and COMMIT TRANSACTION statements to undo any data damage:

    BEGIN
    BEGIN TRANSACTION

    <first batch>
    IF @@error <> 0
        begin
        RAISERROR ('first batch failed',16,-1)
        ROLLBACK TRANSACTION
        RETURN
        end

    <second batch>
    IF @@error <> 0
        begin
        RAISERROR ('second batch failed',16,-1)
        ROLLBACK TRANSACTION
        RETURN
        end

    PRINT 'WIN!'
    COMMIT TRANSACTION
    END


I didn't use the raiseerror solution, because it failed as I didn't have admin permissions. I extended the noexec on/off solution with the transaction handling as follows:

set noexec off

begin transaction
go

<First batch, do something here>
go
if @@error != 0 set noexec on;

<Second batch, do something here>
go
if @@error != 0 set noexec on;

<... etc>

declare @finished bit;
set @finished = 1;

SET noexec off;

IF @finished = 1
BEGIN
    PRINT 'Committing changes'
    COMMIT TRANSACTION
END
ELSE
BEGIN
    PRINT 'Errors occured. Rolling back changes'
    ROLLBACK TRANSACTION
END

Apparently the compiler "understands" the @finished variable in the IF, even if there was an error and the execution was disabled. However, the value is set to 1 only if the execution was not disabled. Hence I can nicely commit or rollback the transaction accordingly.


You could try something like this... If you are using Try block... The error level 16, (or most of application error), immediately transfers the control to the CATCH block without executing any further statements in the try block...

    Begin Transaction

Begin Try

                    --  Do your Stuff

        If (@@RowCount <> 1) -- Error condition
        Begin
            Raiserror('Error Message',16,1)
        End


    Commit
End Try
Begin Catch
    IF @@Trancount > 0
    begin
        Rollback Transaction
    End

    Declare @ErrMsg varchar(4000), @Errseverity int

    SELECT @ErrMsg = ERROR_MESSAGE(),
          @ErrSeverity = ERROR_SEVERITY()

    RAISERROR(@ErrMsg, @ErrSeverity, 1)     
End Catch

Hope this helps...


SET XACT_ABORT ON
BEGIN TRAN

-- Batch 1

GO

if @@TRANCOUNT = 0 
SET NOEXEC ON;
GO

-- Batch 2

GO

if @@TRANCOUNT = 0 
SET NOEXEC ON;
GO

-- Batch 3

GO

if @@TRANCOUNT > 0 
COMMIT
GO
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜