开发者

handling transaction errors when objects don't exist

I found and article in the MSDN Lbrary explaining that try/catch does not handle errors thrown when an object cannot be found. SO, even though I wrap a transaction in a try/catch, the rollback phrase will not execute:

BEGIN TRY
BEGIN TRANSACTION

    SELECT 1 FROM dbo.TableDoesNotExists
    PRINT ' Should not see this'
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION
    SELECT
            ERROR_MESSAGE()
END CATCH

--PRINT 'Error Number before go: ' + CAST(@@Error AS VARCHAR)

go
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR)
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR)

What's the recommended way to handle errors thrown when an object does no开发者_StackOverflow社区t exists, especially when there is a transaction involved. Should I tack this bit of code in place of the last two print statements:

IF @@ERROR <> 0 AND @@TRANCOUNT > 0
BEGIN   
    PRINT 'Rolling back txn'
    ROLLBACK TRANSACTION
END 

go

PRINT 'Transaction Count again: ' + CAST(@@TRANCOUNT AS VARCHAR)


You can test for the existence of an object with OBJECT_ID():

IF OBJECT_ID('MyTable') IS NULL RAISERROR('Could not find MyTable.', 18, 0)


Why are you trying to retrieve data from a table which does not exist?

The fundamental building block of a database is a table. Not knowing what is in your schema is essentially trying to use SQL as a dynamic language, which it is not.

I would rethink your design; without knowing more about the tables in your database and its intended use it's hard for others to help in this regard. Add some more information to your question please.

EDIT I've had a read of BOL and the recommended way to handle errors when an object does not exist is as follows:

You can use TRY…CATCH to handle errors that occur during compilation or statement-level recompilation by executing the error-generating code in a separate batch within the TRY block. For example, you do this by placing the code in a stored procedure or by executing a dynamic Transact-SQL statement using sp_executesql. This allows TRY…CATCH to catch the error at a higher level of execution than the error occurrence.

I tested this out using the following procedure

CREATE PROCEDURE [dbo].[BrokenProcedure]
AS
BEGIN
    SET NOCOUNT ON;
    SELECT * FROM MissingTable
END
GO

Then called it within a TRY..CATCH block:

BEGIN TRY
    PRINT 'Error Number before: ' + CAST(@@Error AS VARCHAR)
    EXECUTE [dbo].[BrokenProcedure] 
    PRINT ' Should not see this'
END TRY
BEGIN CATCH
    PRINT 'Error Number in catch: ' + CAST(@@Error AS VARCHAR)
END CATCH

Resulting in the following output:

Error Number before: 0

Error Number in catch: 208

It's not a perfect solution as you will have to create procedures (or use dynamic SQL) for all of your table access, but it's the method recommend by MS.


Now, you've hit on an interesting issue (well, to me anyway). You should not start a transaction because the batch won't compile. However, it can compile and then statement level recompilation fails later.

See this question What is wrong with my Try Catch in T-SQL?

However, in either case you can use SET XACT_ABORT ON. This adds predictability because one effect is to automatically roll back any transaction. It also suppress error 266. See this SO question too

SET XACT_ABORT ON
BEGIN TRY
    BEGIN TRANSACTION

    SELECT 1 FROM dbo.TableDoesNotExists
    PRINT ' Should not see this'
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    -- not needed, but looks weird without a rollback.
    -- you could forget SET XACT_ABORT ON
    -- Use XACT_STATE avoid double rollback errors
    IF XACT_STATE() <> 0
        ROLLBACK TRANSACTION

    SELECT
            ERROR_MESSAGE()
END CATCH

go  
--note, this can't be guaranteed to give anything
PRINT 'Error Count After go: ' + CAST(@@Error AS VARCHAR)
PRINT 'Transaction Count ' + CAST(@@TRANCOUNT AS VARCHAR)
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜