2010-05-19 52 views
5

Tôi không phải là chuyên gia về Máy chủ SQl. Đây có phải là mẫu hợp lệ để xử lý các lỗi trong một loạt lệnh SELECT, INSERT ... trong SQl SERVER không? (Tôi sử dụng v.2008)Mẫu xử lý lỗi SQL Server

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

    BEGIN CATCH 
     ROLLBACK TRANSACTION 
    END CATCH 

Cảm ơn

Trả lời

6

Tôi sử dụng một cái gì đó như thế này:

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 

Vì bạn chỉ đang thực hiện một lô a batch of SELECT, INSERT, bạn có thể chỉ cần loại bỏ các thủ tục tạo và khai báo tham số và có dòng đầu tiên bắt đầu tại BEGIN TRY. Ngoài ra, vì bạn không tạo quy trình, hãy thay thế bất kỳ câu lệnh RETURN nào bằng GOTO TheEnd và thêm nhãn TheEnd: ở cuối tập lệnh.

+0

Đó là VERY hoàn thành, cảm ơn. Tôi thực sự đang tạo ra một quy trình: Tôi đã đơn giản hóa câu hỏi của mình một chút. Rất vui với @@ ROWCOUNT và @@ TRANCOUNT tôi đã học hôm nay. Tôi luôn tránh được proc được lưu trữ lâu dài, thay vào đó gọi bit và từng phần 1 từ Access (cái mà tôi thực sự làm chủ). Cảm thấy như nhận được "chuyên nghiệp" bây giờ ;-) –

3

Gần:

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; 

này được lấy từ các tài liệu MSDN trên try/catch nơi ví dụ khác có thể được tìm thấy: http://msdn.microsoft.com/en-us/library/ms175976.aspx

+0

Đẹp và nhanh chóng. Cảm ơn –

+1

Tôi luôn đặt mọi thứ, bao gồm 'BEGIN TRANSACTION' và' COMMIT' trong khối TRY. Bạn có KHÔNG muốn bắt gặp sự cố khi tạo hoặc cam kết giao dịch không? –