2013-05-21 48 views
5

Chúng tôi đang trải qua một quá trình chuyển đổi từ DB2 sang SQL Server 2008R2 và tôi hơi không quen với TSQL. Bất kỳ sự trợ giúp nào để hiểu rõ hơn về những gì đang xảy ra sẽ tốt đẹp. Chúng tôi đã tạo một quy trình gọi là RethrowError dưới dạng:SQL SERVER 2008R2 Giao dịch lồng nhau với RAISERROR

CREATE PROCEDURE RethrowError 
AS 
BEGIN 
    -- Return if there is no error information to retrieve. 
    IF ERROR_NUMBER() IS NULL 
     RETURN; 
PRINT 'yo error'; 

    DECLARE 
     @ErrorMessage NVARCHAR(4000), 
     @ErrorNumber  INT, 
     @ErrorSeverity INT, 
     @ErrorState  INT, 
     @ErrorLine  INT, 
     @ErrorProcedure NVARCHAR(200); 

    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR. 
    SELECT 
     @ErrorNumber  = ERROR_NUMBER(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState  = ERROR_STATE(), 
     @ErrorLine  = ERROR_LINE(), 
     @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-'); 

    -- Build the message string that will contain original 
    -- error information. 
    SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 
          'Message: '+ ERROR_MESSAGE(); 
PRINT 'yo doin something'; 

    -- Raise an error: msg_str parameter of RAISERROR will contain 
    -- the original error information. 
    RAISERROR 
     (
     @ErrorMessage, 
     @ErrorSeverity, 
     1,    
     @ErrorNumber, -- parameter: original error number. 
     @ErrorSeverity, -- parameter: original error severity. 
     @ErrorState,  -- parameter: original error state. 
     @ErrorProcedure, -- parameter: original error procedure name. 
     @ErrorLine  -- parameter: original error line number. 
     ); 
PRINT 'yo end'; 

    RETURN; 
END 
GO 

Lý do chúng tôi tạo thủ tục là hoàn toàn mở rộng lỗi trong tương lai mà không phải chạm vào tất cả các thủ tục. Tôi đã thêm một số dòng IN cho mục đích gỡ lỗi.

câu hỏi chính của tôi là chúng ta có thủ tục A và trên thất bại nó thực thi RethrowError và tôi sẽ thấy tin nhắn

yo error 
yo doin something 
yo end 

như mong đợi.

CREATE PROCEDURE dbo.A 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE & SET VARIABLES; 
BEGIN TRY 
    BEGIN TRANSACTION MaintainTarget 

    DO SOME STUFF 
END TRY 
BEGIN CATCH 
    EXEC RethrowError; 

    IF (XACT_STATE()) = -1 
    BEGIN 
     PRINT 
      N'The transaction is in an uncommittable state. ' + 
      'Rolling back transaction.' 
     ROLLBACK TRANSACTION; 
    END; 


    IF (XACT_STATE()) = 1 
    BEGIN 

     PRINT 
      N'The transaction is committable. ' + 
      'Rolling back transaction.' 
     ROLLBACK TRANSACTION; 
    END; 

    RETURN -101; 
END CATCH; 
RETURN; 
END 

GO 

Tuy nhiên, chúng tôi đã tạo một thủ tục mà thực hiện nhiều thủ tục và khi một thủ tục lồng nhau (ví dụ thủ tục Một được gọi bởi thủ tục B) không những thông điệp duy nhất tôi thấy là

yo error 
yo doin something 

tôi Tôi không hiểu tại sao tin nhắn cuối cùng không còn xuất hiện nữa.

Quy trình B tương tự như quy trình A nhưng có một chút khác biệt trong sản lượng đánh bắt.

CREATE PROCEDURE dbo.B 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE & SET VARIABLES; 
BEGIN TRY  
    DO SOME STUFF 
END TRY 
BEGIN CATCH 
COMMIT; 

RETURN -101; 
END CATCH; 
RETURN; 
END 

Bất kỳ trợ giúp nào để hiểu rõ hơn những gì đang xảy ra sẽ được đánh giá cao.

Trả lời

3

Tôi cho phép bản thân mình chỉnh sửa mã của bạn để bắt chước bahaviour, nhưng giữ cho nó đơn giản (công việc của bạn, thực sự;).

procA của bạn hoạt động tốt, bởi vì thủ tục RethrowError đang được gọi bên trong khối CATCH của procA và mọi thứ thực thi. Nhưng trong trường hợp thứ hai của bạn, tất cả vẫn xảy ra bên trong khối TRY của procB! Vì vậy, CATCH một phần của procB cháy ngay sau khi RAISERROR trong RethrowError được gọi.

ví dụ đơn giản này cho thấy hành vi này của try-catch:

begin try 
    select 1/0 
    print 'doesnt show - div error' 
end try 
begin catch 
    print 'oops' 
    select 1/0 
    print 'this one shows because its in CATCH!' 
end catch 

Và đây là mã đơn giản của bạn:

-- "proc B" start 
begin try 
    -- "proc A" start (works fine alone) 
    begin try 
     begin tran 
     select 1/0 --error 
    end try 
    begin catch 
     print 'yo error'; 
     RAISERROR ('RE from RethrowError', 16, 1) --comment this out and see what happens 
     print 'yo end'; 

     IF (XACT_STATE())=-1 or (XACT_STATE())=1 
     BEGIN 
      PRINT N'Rolling back transaction.' 
      ROLLBACK TRANSACTION; 
     end 
    end catch -- "proc A" ends 
end try 
begin catch 
    select error_message(), error_severity(), error_state() -- 
    print 'outer catch'; 
    commit; 
end catch; 

Hope this helps.

+1

+1. Để thêm vào đó, [hãy cẩn thận với các trình xử lý lỗi lồng nhau trong SQL Server 2008] (http://dba.stackexchange.com/q/23805/5203). – GSerg

+0

Cảm ơn, bây giờ hoàn toàn rõ ràng. Tôi sẽ phải ghi nhớ để làm cho mọi thứ đơn giản hơn :). – jabrown

Các vấn đề liên quan