当对象不存在时处理事务错误

时间:2010-12-10 16:47:43

标签: sql transactions try-catch

我在MSDN Lbrary中找到并且文章解释说try / catch不处理无法找到对象时抛出的错误。所以,即使我在try / catch中包装一个事务,回滚短语也不会执行:

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)

当对象不存在时,特别是涉及事务时,处理错误的推荐方法是什么?我应该用这一段代码来代替最后两个打印语句:

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

go

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

3 个答案:

答案 0 :(得分:1)

您可以使用OBJECT_ID()来测试对象是否存在:

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

答案 1 :(得分:0)

您为什么要尝试从不存在的表中检索数据?

数据库的基本构建块是一个表。不知道模式中的内容本质上是尝试将SQL用作动态语言,而不是。

我会重新考虑你的设计;如果不了解数据库中的表及其预期用途,其他人很难在这方面提供帮助。请在您的问题中添加更多信息。

修改 我已经阅读了BOL,并且当对象不存在时,建议的处理错误的方法如下:

  

您可以使用TRY ... CATCH来处理错误   在编译期间发生的   语句级重新编译   执行错误生成代码   TRY块中的单独批次。   例如,您可以通过放置来完成此操作   存储过程中的代码或   执行动态Transact-SQL   使用sp_executesql的语句。这个   允许TRY ... CATCH捕获错误   执行程度高于   错误发生。

我使用以下程序对此进行了测试

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

然后在TRY..CATCH块中调用它:

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

导致以下输出:

  

错误编号:0

     

catch中的错误号:208

这不是一个完美的解决方案,因为您必须为所有表访问创建过程(或使用动态SQL),但这是MS推荐的方法。

答案 2 :(得分:0)

现在,你已经遇到了一个有趣的问题(好吧,无论如何,对我来说)。您不应该启动事务,因为批处理将无法编译。但是,它可以编译,然后语句级别重新编译将失败。

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

但是,在 情况下,您可以使用SET XACT_ABORT ON。这增加了可预测性,因为一种效果是自动回滚任何事务。它还会抑制错误266.请参阅此SO question

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)