2010-05-19 44 views
5

我不是SQl服务器上的专家。这是一个有效的模式,用于在SQl SERVER中处理一批SELECT,INSERT ...中的错误? (我用v.2008)SQL Server错误处理模式

BEGIN TRANSACTION 
    BEGIN TRY 
     -- statement 1 
     -- statement 2 
     -- statement 3 
     COMMIT TRANSACTION 
    END TRY 

    BEGIN CATCH 
     ROLLBACK TRANSACTION 
    END CATCH 

由于

回答

6

我使用类似这样的东西:

CREATE PROCEDURE ErrorHandlingPattern 
( @intParam  int 
    ,@varcharParam varchar(10) 
    ,@dateParam  datetime 
) 
AS 

BEGIN TRY 
    SET NOCOUNT ON 
    DECLARE @Rows    int   --store @@ROWCOUNT in this 
      ,@ErrorMsg   varchar(500) --temp string to build the contents of messages passed into RAISERROR calls 
      ,@LogInfo   varchar(5000) --will hold any info necessary for error debugging, append to this throughout the procedure with important info 
      ,@TransactionCount int   

    SELECT @[email protected]@TRANCOUNT 
      ,@LogInfo='@intParam='  +ISNULL(''''+CONVERT(varchar(10), @intParam  )+'''','NULL') 
       +', @varcharParam=' +ISNULL(''''+      @varcharParam +'''','NULL') 
       +', @dateParam=' +ISNULL(''''+CONVERT(varchar(10), @dateParam,121 )+'''','NULL') 
       +'; @@TRANCOUNT=' +ISNULL(''''+CONVERT(varchar(10), @@TRANCOUNT )+'''','NULL') 

    --validate parameters 
    IF @intParam .... 
    BEGIN --logical error 
     SET @ErrorMsg='Error, invalid value for @intParam: '+ISNULL(''''+CONVERT(varchar(10),@intParam)+'''','NULL') 
     RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block 
    END 

    IF @TransactionCount=0 --if we are already in a transaction, no need to start another, nesting transactions +rollback=warnings about transaction count not being the same as when the procedure started. 
    BEGIN 
     BEGIN TRANSACTION 
    END 

    --do your work here.... 
    INSERT/UPDATE/DELETE... 
    SELECT @[email protected]@ROWCOUNT 

    IF @Rows!=ExpectedValue 
    BEGIN --logical error 
     SET @ErrorMsg='Error, INSERT/UPDATE/DELETE of tableXYZ resulted in '+ISNULL(''''+CONVERT(varchar(10),@Rows)+'''','NULL')+' rows affected' 
     RAISERROR(@ErrorMsg,16,1) --send control to the BEGIN CATCH block 
    END 

    --append improtant info to log string 
    SET @LogInfo=ISNULL(@LogInfo,'')+'; INSERT/UPDATE/DELETE of tableXYZ resulted in '+ISNULL(''''+CONVERT(varchar(10),@Rows)+'''','NULL')+' rows affected' 

    IF @TransactionCount=0 --only end the transaction if it started here 
    BEGIN 
     COMMIT --put in try block to be able to catch any problems committing 
    END 
END TRY 
BEGIN CATCH 

    IF XACT_STATE()!=0 --if there is any error end the transaction ASAP 
    BEGIN 
     ROLLBACK TRANSACTION 
    END 

    --will echo back the complete original error message 
    DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int 
    SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE() 
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine) 

    --because the transaction was ROLLBACKed this insert will be recorded in the database 
    INSERT INTO YourErrorLog (...) VALUES (...ISNULL(@ErrorMessage,'')+ISNULL(@LogInfo,'')) 

    RETURN 999 

END CATCH 

RETURN 0 
GO 

由于您只是在执行一批a batch of SELECT, INSERT,因此您可以删除CREATE PROCEDURE和参数声明并使第一行开始于BEGIN TRY。另外,因为您没有创建过程,请将所有RETURN语句替换为GOTO TheEnd,并在脚本底部添加一个TheEnd:标签。

+0

这是非常完整的,谢谢。我确实在创建一个程序:我简化了一下我的问题。非常满意我今天学到的@@ ROWCOUNT和@@ TRANCOUNT。我总是避免长时间存储过程,而是从Access(我真的掌握)中逐个调用一些零件。感觉现在变成“亲”;-) – 2010-05-19 12:25:56

3

近:

BEGIN TRANSACTION; 

BEGIN TRY 
    -- Generate a constraint violation error. 
    DELETE FROM Production.Product 
    WHERE ProductID = 980; 
END TRY 
BEGIN CATCH 
    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; 

    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION; 
END CATCH; 

IF @@TRANCOUNT > 0 
    COMMIT TRANSACTION; 

这是从TRY/CATCH MSDN文档采取其中其它实例中,可以发现:http://msdn.microsoft.com/en-us/library/ms175976.aspx

+0

不错,很快。谢谢 – 2010-05-19 10:49:17

+1

我总是将所有内容放在TRY块中,包括'BEGIN TRANSACTION'和'COMMIT'。您是否不希望发现创建或提交交易的问题? – 2010-05-19 12:09:33